Merge "Switch from Droid -> Noto for RS fonts."
diff --git a/Android.mk b/Android.mk
index 573f46a..216d8a2d4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -77,9 +77,9 @@
core/java/android/app/ISearchManagerCallback.aidl \
core/java/android/app/IServiceConnection.aidl \
core/java/android/app/IStopUserCallback.aidl \
- core/java/android/app/task/ITaskCallback.aidl \
- core/java/android/app/task/ITaskManager.aidl \
- core/java/android/app/task/ITaskService.aidl \
+ core/java/android/app/job/IJobCallback.aidl \
+ core/java/android/app/job/IJobScheduler.aidl \
+ core/java/android/app/job/IJobService.aidl \
core/java/android/app/IThumbnailRetriever.aidl \
core/java/android/app/ITransientNotification.aidl \
core/java/android/app/IUiAutomationConnection.aidl \
@@ -94,10 +94,10 @@
core/java/android/app/backup/IFullBackupRestoreObserver.aidl \
core/java/android/app/backup/IRestoreObserver.aidl \
core/java/android/app/backup/IRestoreSession.aidl \
- core/java/android/app/maintenance/IIdleCallback.aidl \
- core/java/android/app/maintenance/IIdleService.aidl \
core/java/android/bluetooth/IBluetooth.aidl \
core/java/android/bluetooth/IBluetoothA2dp.aidl \
+ core/java/android/bluetooth/IBluetoothA2dpSink.aidl \
+ core/java/android/bluetooth/IBluetoothAvrcpController.aidl \
core/java/android/bluetooth/IBluetoothCallback.aidl \
core/java/android/bluetooth/IBluetoothHeadset.aidl \
core/java/android/bluetooth/IBluetoothHeadsetPhone.aidl \
@@ -110,6 +110,7 @@
core/java/android/bluetooth/IBluetoothPbap.aidl \
core/java/android/bluetooth/IBluetoothMap.aidl \
core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
+ core/java/android/bluetooth/IBluetoothHeadsetClient.aidl \
core/java/android/bluetooth/IBluetoothGatt.aidl \
core/java/android/bluetooth/IBluetoothGattCallback.aidl \
core/java/android/bluetooth/IBluetoothGattServerCallback.aidl \
@@ -147,10 +148,9 @@
core/java/android/hardware/ISerialManager.aidl \
core/java/android/hardware/display/IDisplayManager.aidl \
core/java/android/hardware/display/IDisplayManagerCallback.aidl \
- core/java/android/hardware/hdmi/IHdmiCecListener.aidl \
- core/java/android/hardware/hdmi/IHdmiCecService.aidl \
core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
core/java/android/hardware/hdmi/IHdmiControlService.aidl \
+ core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl \
core/java/android/hardware/hdmi/IHdmiHotplugEventListener.aidl \
core/java/android/hardware/input/IInputManager.aidl \
core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
@@ -307,14 +307,15 @@
media/java/android/media/IRemoteVolumeObserver.aidl \
media/java/android/media/IRingtonePlayer.aidl \
media/java/android/media/IVolumeController.aidl \
- media/java/android/media/routeprovider/IRouteConnection.aidl \
- media/java/android/media/routeprovider/IRouteProvider.aidl \
- media/java/android/media/routeprovider/IRouteProviderCallback.aidl \
- media/java/android/media/session/ISessionController.aidl \
- media/java/android/media/session/ISessionControllerCallback.aidl \
- media/java/android/media/session/ISession.aidl \
- media/java/android/media/session/ISessionCallback.aidl \
- media/java/android/media/session/ISessionManager.aidl \
+ media/java/android/media/routeprovider/IRouteConnection.aidl \
+ media/java/android/media/routeprovider/IRouteProvider.aidl \
+ media/java/android/media/routeprovider/IRouteProviderCallback.aidl \
+ media/java/android/media/session/IActiveSessionsListener.aidl \
+ media/java/android/media/session/ISessionController.aidl \
+ media/java/android/media/session/ISessionControllerCallback.aidl \
+ media/java/android/media/session/ISession.aidl \
+ media/java/android/media/session/ISessionCallback.aidl \
+ media/java/android/media/session/ISessionManager.aidl \
media/java/android/media/tv/ITvInputClient.aidl \
media/java/android/media/tv/ITvInputHardware.aidl \
media/java/android/media/tv/ITvInputHardwareCallback.aidl \
@@ -342,6 +343,7 @@
telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
telephony/java/com/android/internal/telephony/ISms.aidl \
telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
+ telephony/java/com/android/internal/telephony/ISub.aidl \
wifi/java/android/net/wifi/IWifiManager.aidl \
wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl \
wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
@@ -606,8 +608,12 @@
framework_docs_LOCAL_DROIDDOC_HTML_DIR := docs/html
# The since flag (-since N.xml API_LEVEL) is used to add API Level information
# to the reference documentation. Must be in order of oldest to newest.
+#
+# Conscrypt (com.android.org.conscrypt) is an implementation detail and should
+# not be referenced in the documentation.
framework_docs_LOCAL_DROIDDOC_OPTIONS := \
-knowntags ./frameworks/base/docs/knowntags.txt \
+ -hidePackage com.android.org.conscrypt \
-since $(SRC_API_DIR)/1.xml 1 \
-since $(SRC_API_DIR)/2.xml 2 \
-since $(SRC_API_DIR)/3.xml 3 \
@@ -701,7 +707,7 @@
$(INTERNAL_PLATFORM_API_FILE): $(full_target)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
-# ==== the private api stubs ===================================
+# ==== the system api stubs ===================================
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_API_CHECK_SRC_FILES)
@@ -713,12 +719,12 @@
LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
-LOCAL_MODULE := private-api-stubs
+LOCAL_MODULE := system-api-stubs
LOCAL_DROIDDOC_OPTIONS:=\
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
- -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_private_stubs_current_intermediates/src \
- -showAnnotation android.annotation.PrivateApi \
+ -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_system_stubs_current_intermediates/src \
+ -showAnnotation android.annotation.SystemApi \
-nodocs
LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
diff --git a/CleanSpec.mk b/CleanSpec.mk
index f3bb9b6..1968a78 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -34,9 +34,9 @@
# made today requires touching the same file, just copy the old
# touch step and add it to the end of the list.
#
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
# For example:
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
@@ -193,7 +193,16 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app/wearable)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/tv/ITv*)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/app/task)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app/task)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/app/TaskManager)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app/maintenance)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/classes/android/app/maintenance)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes/android/app/maintenance)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes/android/app/maintenance)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app/maintenance)
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git "a/\\" "b/\\"
deleted file mode 100644
index 1d25d33..0000000
--- "a/\\"
+++ /dev/null
@@ -1,19 +0,0 @@
-Doc update: new Volley class
-
-Change-Id: Ife3a9a64439e07aaaf92a22adc6d1678138caf7d
-
-# Please enter the commit message for your changes. Lines starting
-# with '#' will be ignored, and an empty message aborts the commit.
-# On branch volley
-# Changes to be committed:
-# new file: docs/html/images/training/volley-request.png
-# modified: docs/html/training/basics/network-ops/connecting.jd
-# modified: docs/html/training/basics/network-ops/index.jd
-# modified: docs/html/training/training_toc.cs
-# new file: docs/html/training/volley/index.jd
-# new file: docs/html/training/volley/request-custom.jd
-# new file: docs/html/training/volley/request.jd
-# new file: docs/html/training/volley/requestqueue.jd
-# new file: docs/html/training/volley/setup.jd
-# new file: docs/html/training/volley/simple.jd
-#
diff --git a/api/current.txt b/api/current.txt
index 234126b..af989e8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9,7 +9,6 @@
field public static final java.lang.String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
field public static final java.lang.String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
field public static final java.lang.String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
- field public static final java.lang.String ACCESS_INPUT_FLINGER = "android.permission.ACCESS_INPUT_FLINGER";
field public static final java.lang.String ACCESS_LOCATION_EXTRA_COMMANDS = "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS";
field public static final java.lang.String ACCESS_MOCK_LOCATION = "android.permission.ACCESS_MOCK_LOCATION";
field public static final java.lang.String ACCESS_NETWORK_STATE = "android.permission.ACCESS_NETWORK_STATE";
@@ -249,7 +248,7 @@
field public static final int actionBarTabBarStyle = 16843508; // 0x10102f4
field public static final int actionBarTabStyle = 16843507; // 0x10102f3
field public static final int actionBarTabTextStyle = 16843509; // 0x10102f5
- field public static final int actionBarTheme = 16843828; // 0x1010434
+ field public static final int actionBarTheme = 16843827; // 0x1010433
field public static final int actionBarWidgetTheme = 16843671; // 0x1010397
field public static final int actionButtonStyle = 16843480; // 0x10102d8
field public static final int actionDropDownStyle = 16843479; // 0x10102d7
@@ -266,7 +265,7 @@
field public static final int actionModeSplitBackground = 16843677; // 0x101039d
field public static final int actionModeStyle = 16843668; // 0x1010394
field public static final int actionOverflowButtonStyle = 16843510; // 0x10102f6
- field public static final int actionOverflowMenuStyle = 16843847; // 0x1010447
+ field public static final int actionOverflowMenuStyle = 16843846; // 0x1010446
field public static final int actionProviderClass = 16843657; // 0x1010389
field public static final int actionViewClass = 16843516; // 0x10102fc
field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
@@ -321,6 +320,8 @@
field public static final int backgroundDimEnabled = 16843295; // 0x101021f
field public static final int backgroundSplit = 16843659; // 0x101038b
field public static final int backgroundStacked = 16843658; // 0x101038a
+ field public static final int backgroundTint = 16843885; // 0x101046d
+ field public static final int backgroundTintMode = 16843886; // 0x101046e
field public static final int backupAgent = 16843391; // 0x101027f
field public static final int banner = 16843762; // 0x10103f2
field public static final int baseline = 16843548; // 0x101031c
@@ -345,6 +346,8 @@
field public static final int buttonStyleInset = 16842826; // 0x101004a
field public static final int buttonStyleSmall = 16842825; // 0x1010049
field public static final int buttonStyleToggle = 16842827; // 0x101004b
+ field public static final int buttonTint = 16843889; // 0x1010471
+ field public static final int buttonTintMode = 16843890; // 0x1010472
field public static final int cacheColorHint = 16843009; // 0x1010101
field public static final int calendarViewShown = 16843596; // 0x101034c
field public static final int calendarViewStyle = 16843613; // 0x101035d
@@ -385,22 +388,22 @@
field public static final int codes = 16843330; // 0x1010242
field public static final int collapseColumns = 16843083; // 0x101014b
field public static final int color = 16843173; // 0x10101a5
- field public static final int colorAccent = 16843832; // 0x1010438
+ field public static final int colorAccent = 16843831; // 0x1010437
field public static final int colorActivatedHighlight = 16843664; // 0x1010390
field public static final int colorBackground = 16842801; // 0x1010031
field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
- field public static final int colorButtonNormal = 16843822; // 0x101042e
- field public static final int colorControlActivated = 16843821; // 0x101042d
- field public static final int colorControlHighlight = 16843823; // 0x101042f
- field public static final int colorControlNormal = 16843820; // 0x101042c
+ field public static final int colorButtonNormal = 16843821; // 0x101042d
+ field public static final int colorControlActivated = 16843820; // 0x101042c
+ field public static final int colorControlHighlight = 16843822; // 0x101042e
+ field public static final int colorControlNormal = 16843819; // 0x101042b
field public static final int colorFocusedHighlight = 16843663; // 0x101038f
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
field public static final int colorLongPressedHighlight = 16843662; // 0x101038e
field public static final int colorMultiSelectHighlight = 16843665; // 0x1010391
field public static final int colorPressedHighlight = 16843661; // 0x101038d
- field public static final int colorPrimary = 16843830; // 0x1010436
- field public static final int colorPrimaryDark = 16843831; // 0x1010437
+ field public static final int colorPrimary = 16843829; // 0x1010435
+ field public static final int colorPrimaryDark = 16843830; // 0x1010436
field public static final int columnCount = 16843639; // 0x1010377
field public static final int columnDelay = 16843215; // 0x10101cf
field public static final int columnOrderPreserved = 16843640; // 0x1010378
@@ -463,7 +466,7 @@
field public static final int dividerHorizontal = 16843564; // 0x101032c
field public static final int dividerPadding = 16843562; // 0x101032a
field public static final int dividerVertical = 16843530; // 0x101030a
- field public static final int documentLaunchMode = 16843848; // 0x1010448
+ field public static final int documentLaunchMode = 16843847; // 0x1010447
field public static final int drawSelectorOnTop = 16843004; // 0x10100fc
field public static final int drawable = 16843161; // 0x1010199
field public static final int drawableBottom = 16843118; // 0x101016e
@@ -493,7 +496,7 @@
field public static final deprecated int editable = 16843115; // 0x101016b
field public static final int editorExtras = 16843300; // 0x1010224
field public static final int elegantTextHeight = 16843871; // 0x101045f
- field public static final int elevation = 16843843; // 0x1010443
+ field public static final int elevation = 16843842; // 0x1010442
field public static final int ellipsize = 16842923; // 0x10100ab
field public static final int ems = 16843096; // 0x1010158
field public static final int enabled = 16842766; // 0x101000e
@@ -503,9 +506,9 @@
field public static final int entries = 16842930; // 0x10100b2
field public static final int entryValues = 16843256; // 0x10101f8
field public static final int eventsInterceptionEnabled = 16843389; // 0x101027d
- field public static final int excludeClass = 16843845; // 0x1010445
+ field public static final int excludeClass = 16843844; // 0x1010444
field public static final int excludeFromRecents = 16842775; // 0x1010017
- field public static final int excludeId = 16843844; // 0x1010444
+ field public static final int excludeId = 16843843; // 0x1010443
field public static final int excludeViewName = 16843856; // 0x1010450
field public static final int exitFadeDuration = 16843533; // 0x101030d
field public static final int expandableListPreferredChildIndicatorLeft = 16842834; // 0x1010052
@@ -555,6 +558,8 @@
field public static final int footerDividersEnabled = 16843311; // 0x101022f
field public static final int foreground = 16843017; // 0x1010109
field public static final int foregroundGravity = 16843264; // 0x1010200
+ field public static final int foregroundTint = 16843887; // 0x101046f
+ field public static final int foregroundTintMode = 16843888; // 0x1010470
field public static final int format = 16843013; // 0x1010105
field public static final int format12Hour = 16843722; // 0x10103ca
field public static final int format24Hour = 16843723; // 0x10103cb
@@ -601,7 +606,7 @@
field public static final int headerBackground = 16843055; // 0x101012f
field public static final int headerDividersEnabled = 16843310; // 0x101022e
field public static final int height = 16843093; // 0x1010155
- field public static final int hideOnContentScroll = 16843846; // 0x1010446
+ field public static final int hideOnContentScroll = 16843845; // 0x1010445
field public static final int hint = 16843088; // 0x1010150
field public static final int homeAsUpIndicator = 16843531; // 0x101030b
field public static final int homeLayout = 16843549; // 0x101031d
@@ -637,6 +642,8 @@
field public static final int indeterminateDuration = 16843069; // 0x101013d
field public static final int indeterminateOnly = 16843066; // 0x101013a
field public static final int indeterminateProgressStyle = 16843544; // 0x1010318
+ field public static final int indeterminateTint = 16843883; // 0x101046b
+ field public static final int indeterminateTintMode = 16843884; // 0x101046c
field public static final int indicatorEnd = 16843730; // 0x10103d2
field public static final int indicatorLeft = 16843021; // 0x101010d
field public static final int indicatorRight = 16843022; // 0x101010e
@@ -707,7 +714,6 @@
field public static final int l_resource_pad23 = 16843770; // 0x10103fa
field public static final int l_resource_pad24 = 16843769; // 0x10103f9
field public static final int l_resource_pad25 = 16843768; // 0x10103f8
- field public static final int l_resource_pad26 = 16843767; // 0x10103f7
field public static final int l_resource_pad3 = 16843790; // 0x101040e
field public static final int l_resource_pad4 = 16843789; // 0x101040d
field public static final int l_resource_pad5 = 16843788; // 0x101040c
@@ -808,6 +814,7 @@
field public static final int maxLength = 16843104; // 0x1010160
field public static final int maxLevel = 16843186; // 0x10101b2
field public static final int maxLines = 16843091; // 0x1010153
+ field public static final int maxRecents = 16843848; // 0x1010448
field public static final int maxRows = 16843059; // 0x1010133
field public static final int maxSdkVersion = 16843377; // 0x1010271
field public static final int maxWidth = 16843039; // 0x101011f
@@ -835,7 +842,7 @@
field public static final int navigationBarColor = 16843860; // 0x1010454
field public static final int navigationMode = 16843471; // 0x10102cf
field public static final int negativeButtonText = 16843254; // 0x10101f6
- field public static final int nestedScrollingEnabled = 16843833; // 0x1010439
+ field public static final int nestedScrollingEnabled = 16843832; // 0x1010438
field public static final int nextFocusDown = 16842980; // 0x10100e4
field public static final int nextFocusForward = 16843580; // 0x101033c
field public static final int nextFocusLeft = 16842977; // 0x10100e1
@@ -860,6 +867,7 @@
field public static final int overScrollFooter = 16843459; // 0x10102c3
field public static final int overScrollHeader = 16843458; // 0x10102c2
field public static final int overScrollMode = 16843457; // 0x10102c1
+ field public static final int overlapAnchor = 16843876; // 0x1010464
field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
field public static final int packageNames = 16843649; // 0x1010381
field public static final int padding = 16842965; // 0x10100d5
@@ -885,11 +893,10 @@
field public static final int permissionFlags = 16843719; // 0x10103c7
field public static final int permissionGroup = 16842762; // 0x101000a
field public static final int permissionGroupFlags = 16843717; // 0x10103c5
- field public static final int persistable = 16843824; // 0x1010430
+ field public static final int persistable = 16843823; // 0x101042f
field public static final int persistent = 16842765; // 0x101000d
field public static final int persistentDrawingCache = 16842990; // 0x10100ee
field public static final deprecated int phoneNumber = 16843111; // 0x1010167
- field public static final int pinned = 16843819; // 0x101042b
field public static final int pivotX = 16843189; // 0x10101b5
field public static final int pivotY = 16843190; // 0x10101b6
field public static final int popupAnimationStyle = 16843465; // 0x10102c9
@@ -912,6 +919,8 @@
field public static final int privateImeOptions = 16843299; // 0x1010223
field public static final int process = 16842769; // 0x1010011
field public static final int progress = 16843063; // 0x1010137
+ field public static final int progressBackgroundTint = 16843879; // 0x1010467
+ field public static final int progressBackgroundTintMode = 16843880; // 0x1010468
field public static final int progressBarPadding = 16843545; // 0x1010319
field public static final int progressBarStyle = 16842871; // 0x1010077
field public static final int progressBarStyleHorizontal = 16842872; // 0x1010078
@@ -922,6 +931,8 @@
field public static final int progressBarStyleSmallInverse = 16843400; // 0x1010288
field public static final int progressBarStyleSmallTitle = 16843279; // 0x101020f
field public static final int progressDrawable = 16843068; // 0x101013c
+ field public static final int progressTint = 16843877; // 0x1010465
+ field public static final int progressTintMode = 16843878; // 0x1010466
field public static final int prompt = 16843131; // 0x101017b
field public static final int propertyName = 16843489; // 0x10102e1
field public static final int protectionLevel = 16842761; // 0x1010009
@@ -1002,6 +1013,9 @@
field public static final int scrollbars = 16842974; // 0x10100de
field public static final int scrollingCache = 16843006; // 0x10100fe
field public static final deprecated int searchButtonText = 16843269; // 0x1010205
+ field public static final int searchKeyphrase = 16843873; // 0x1010461
+ field public static final int searchKeyphraseId = 16843872; // 0x1010460
+ field public static final int searchKeyphraseSupportedLocales = 16843874; // 0x1010462
field public static final int searchMode = 16843221; // 0x10101d5
field public static final int searchSettingsDescription = 16843402; // 0x101028a
field public static final int searchSuggestAuthority = 16843222; // 0x10101d6
@@ -1011,6 +1025,8 @@
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int secondaryProgress = 16843064; // 0x1010138
+ field public static final int secondaryProgressTint = 16843881; // 0x1010469
+ field public static final int secondaryProgressTintMode = 16843882; // 0x101046a
field public static final int seekBarStyle = 16842875; // 0x101007b
field public static final int segmentedButtonStyle = 16843568; // 0x1010330
field public static final int selectAllOnFocus = 16843102; // 0x101015e
@@ -1019,7 +1035,7 @@
field public static final int selectableItemBackgroundBorderless = 16843870; // 0x101045e
field public static final int selectedDateVerticalBar = 16843591; // 0x1010347
field public static final int selectedWeekBackgroundColor = 16843586; // 0x1010342
- field public static final int sessionService = 16843840; // 0x1010440
+ field public static final int sessionService = 16843839; // 0x101043f
field public static final int settingsActivity = 16843301; // 0x1010225
field public static final int setupActivity = 16843766; // 0x10103f6
field public static final int shadowColor = 16843105; // 0x1010161
@@ -1041,7 +1057,7 @@
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
- field public static final int slideEdge = 16843827; // 0x1010433
+ field public static final int slideEdge = 16843826; // 0x1010432
field public static final int smallIcon = 16843422; // 0x101029e
field public static final int smallScreens = 16843396; // 0x1010284
field public static final int smoothScrollbar = 16843313; // 0x1010231
@@ -1059,7 +1075,7 @@
field public static final int sspPattern = 16843749; // 0x10103e5
field public static final int sspPrefix = 16843748; // 0x10103e4
field public static final int stackFromBottom = 16843005; // 0x10100fd
- field public static final int stackViewStyle = 16843841; // 0x1010441
+ field public static final int stackViewStyle = 16843840; // 0x1010440
field public static final int starStyle = 16842882; // 0x1010082
field public static final int startColor = 16843165; // 0x101019d
field public static final int startDelay = 16843746; // 0x10103e2
@@ -1102,7 +1118,7 @@
field public static final int strokeOpacity = 16843810; // 0x1010422
field public static final int strokeWidth = 16843811; // 0x1010423
field public static final int subtitle = 16843473; // 0x10102d1
- field public static final int subtitleTextAppearance = 16843826; // 0x1010432
+ field public static final int subtitleTextAppearance = 16843825; // 0x1010431
field public static final int subtitleTextStyle = 16843513; // 0x10102f9
field public static final int subtypeExtraValue = 16843674; // 0x101039a
field public static final int subtypeId = 16843713; // 0x10103c1
@@ -1119,7 +1135,7 @@
field public static final int switchMinWidth = 16843632; // 0x1010370
field public static final int switchPadding = 16843633; // 0x1010371
field public static final int switchPreferenceStyle = 16843629; // 0x101036d
- field public static final int switchStyle = 16843842; // 0x1010442
+ field public static final int switchStyle = 16843841; // 0x1010441
field public static final int switchTextAppearance = 16843630; // 0x101036e
field public static final int switchTextOff = 16843628; // 0x101036c
field public static final int switchTextOn = 16843627; // 0x101036b
@@ -1157,7 +1173,7 @@
field public static final int textAppearanceLargeInverse = 16842819; // 0x1010043
field public static final int textAppearanceLargePopupMenu = 16843521; // 0x1010301
field public static final int textAppearanceListItem = 16843678; // 0x101039e
- field public static final int textAppearanceListItemSecondary = 16843829; // 0x1010435
+ field public static final int textAppearanceListItemSecondary = 16843828; // 0x1010434
field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
field public static final int textAppearanceMedium = 16842817; // 0x1010041
field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
@@ -1214,6 +1230,8 @@
field public static final int thumb = 16843074; // 0x1010142
field public static final int thumbOffset = 16843075; // 0x1010143
field public static final int thumbTextPadding = 16843634; // 0x1010372
+ field public static final int thumbTint = 16843891; // 0x1010473
+ field public static final int thumbTintMode = 16843892; // 0x1010474
field public static final int thumbnail = 16843429; // 0x10102a5
field public static final int tileMode = 16843265; // 0x1010201
field public static final int timeZone = 16843724; // 0x10103cc
@@ -1221,7 +1239,7 @@
field public static final int tintMode = 16843797; // 0x1010415
field public static final int title = 16843233; // 0x10101e1
field public static final int titleCondensed = 16843234; // 0x10101e2
- field public static final int titleTextAppearance = 16843825; // 0x1010431
+ field public static final int titleTextAppearance = 16843824; // 0x1010430
field public static final int titleTextStyle = 16843512; // 0x10102f8
field public static final int toAlpha = 16843211; // 0x10101cb
field public static final int toDegrees = 16843188; // 0x10101b4
@@ -1252,6 +1270,7 @@
field public static final int trimPathEnd = 16843813; // 0x1010425
field public static final int trimPathOffset = 16843814; // 0x1010426
field public static final int trimPathStart = 16843812; // 0x1010424
+ field public static final int tvInputType = 16843767; // 0x10103f7
field public static final int type = 16843169; // 0x10101a1
field public static final int typeface = 16842902; // 0x1010096
field public static final int uiOptions = 16843672; // 0x1010398
@@ -1307,8 +1326,8 @@
field public static final int windowActionBar = 16843469; // 0x10102cd
field public static final int windowActionBarOverlay = 16843492; // 0x10102e4
field public static final int windowActionModeOverlay = 16843485; // 0x10102dd
- field public static final int windowAllowEnterTransitionOverlap = 16843839; // 0x101043f
- field public static final int windowAllowExitTransitionOverlap = 16843838; // 0x101043e
+ field public static final int windowAllowEnterTransitionOverlap = 16843838; // 0x101043e
+ field public static final int windowAllowExitTransitionOverlap = 16843837; // 0x101043d
field public static final int windowAnimationStyle = 16842926; // 0x10100ae
field public static final int windowBackground = 16842836; // 0x1010054
field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
@@ -1319,9 +1338,9 @@
field public static final int windowDrawsSystemBarBackgrounds = 16843858; // 0x1010452
field public static final int windowEnableSplitTouch = 16843543; // 0x1010317
field public static final int windowEnterAnimation = 16842932; // 0x10100b4
- field public static final int windowEnterTransition = 16843834; // 0x101043a
+ field public static final int windowEnterTransition = 16843833; // 0x1010439
field public static final int windowExitAnimation = 16842933; // 0x10100b5
- field public static final int windowExitTransition = 16843835; // 0x101043b
+ field public static final int windowExitTransition = 16843834; // 0x101043a
field public static final int windowFrame = 16842837; // 0x1010055
field public static final int windowFullscreen = 16843277; // 0x101020d
field public static final int windowHideAnimation = 16842935; // 0x10100b7
@@ -1332,8 +1351,8 @@
field public static final int windowNoDisplay = 16843294; // 0x101021e
field public static final int windowNoTitle = 16842838; // 0x1010056
field public static final int windowOverscan = 16843727; // 0x10103cf
- field public static final int windowSharedElementEnterTransition = 16843836; // 0x101043c
- field public static final int windowSharedElementExitTransition = 16843837; // 0x101043d
+ field public static final int windowSharedElementEnterTransition = 16843835; // 0x101043b
+ field public static final int windowSharedElementExitTransition = 16843836; // 0x101043c
field public static final int windowShowAnimation = 16842934; // 0x10100b6
field public static final int windowShowWallpaper = 16843410; // 0x1010292
field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -1341,6 +1360,7 @@
field public static final int windowTitleBackgroundStyle = 16842844; // 0x101005c
field public static final int windowTitleSize = 16842842; // 0x101005a
field public static final int windowTitleStyle = 16842843; // 0x101005b
+ field public static final int windowTransitionBackgroundFadeDuration = 16843875; // 0x1010463
field public static final int windowTranslucentNavigation = 16843760; // 0x10103f0
field public static final int windowTranslucentStatus = 16843759; // 0x10103ef
field public static final int writePermission = 16842760; // 0x1010008
@@ -1865,54 +1885,54 @@
field public static final int TextAppearance_Inverse = 16973887; // 0x103003f
field public static final int TextAppearance_Large = 16973890; // 0x1030042
field public static final int TextAppearance_Large_Inverse = 16973891; // 0x1030043
+ field public static final int TextAppearance_Material = 16974350; // 0x103020e
+ field public static final int TextAppearance_Material_Body1 = 16974552; // 0x10302d8
+ field public static final int TextAppearance_Material_Body2 = 16974551; // 0x10302d7
+ field public static final int TextAppearance_Material_Button = 16974555; // 0x10302db
+ field public static final int TextAppearance_Material_Caption = 16974553; // 0x10302d9
+ field public static final int TextAppearance_Material_DialogWindowTitle = 16974351; // 0x103020f
+ field public static final int TextAppearance_Material_Display1 = 16974547; // 0x10302d3
+ field public static final int TextAppearance_Material_Display2 = 16974546; // 0x10302d2
+ field public static final int TextAppearance_Material_Display3 = 16974545; // 0x10302d1
+ field public static final int TextAppearance_Material_Display4 = 16974544; // 0x10302d0
+ field public static final int TextAppearance_Material_Headline = 16974548; // 0x10302d4
+ field public static final int TextAppearance_Material_Inverse = 16974352; // 0x1030210
+ field public static final int TextAppearance_Material_Large = 16974353; // 0x1030211
+ field public static final int TextAppearance_Material_Large_Inverse = 16974354; // 0x1030212
+ field public static final int TextAppearance_Material_Medium = 16974355; // 0x1030213
+ field public static final int TextAppearance_Material_Medium_Inverse = 16974356; // 0x1030214
+ field public static final int TextAppearance_Material_Menu = 16974554; // 0x10302da
+ field public static final int TextAppearance_Material_SearchResult_Subtitle = 16974357; // 0x1030215
+ field public static final int TextAppearance_Material_SearchResult_Title = 16974358; // 0x1030216
+ field public static final int TextAppearance_Material_Small = 16974359; // 0x1030217
+ field public static final int TextAppearance_Material_Small_Inverse = 16974360; // 0x1030218
+ field public static final int TextAppearance_Material_Subhead = 16974550; // 0x10302d6
+ field public static final int TextAppearance_Material_Title = 16974549; // 0x10302d5
+ field public static final int TextAppearance_Material_Widget = 16974362; // 0x103021a
+ field public static final int TextAppearance_Material_Widget_ActionBar_Menu = 16974363; // 0x103021b
+ field public static final int TextAppearance_Material_Widget_ActionBar_Subtitle = 16974364; // 0x103021c
+ field public static final int TextAppearance_Material_Widget_ActionBar_Subtitle_Inverse = 16974365; // 0x103021d
+ field public static final int TextAppearance_Material_Widget_ActionBar_Title = 16974366; // 0x103021e
+ field public static final int TextAppearance_Material_Widget_ActionBar_Title_Inverse = 16974367; // 0x103021f
+ field public static final int TextAppearance_Material_Widget_ActionMode_Subtitle = 16974368; // 0x1030220
+ field public static final int TextAppearance_Material_Widget_ActionMode_Subtitle_Inverse = 16974369; // 0x1030221
+ field public static final int TextAppearance_Material_Widget_ActionMode_Title = 16974370; // 0x1030222
+ field public static final int TextAppearance_Material_Widget_ActionMode_Title_Inverse = 16974371; // 0x1030223
+ field public static final int TextAppearance_Material_Widget_Button = 16974372; // 0x1030224
+ field public static final int TextAppearance_Material_Widget_DropDownHint = 16974373; // 0x1030225
+ field public static final int TextAppearance_Material_Widget_DropDownItem = 16974374; // 0x1030226
+ field public static final int TextAppearance_Material_Widget_EditText = 16974375; // 0x1030227
+ field public static final int TextAppearance_Material_Widget_IconMenu_Item = 16974376; // 0x1030228
+ field public static final int TextAppearance_Material_Widget_PopupMenu = 16974377; // 0x1030229
+ field public static final int TextAppearance_Material_Widget_PopupMenu_Large = 16974378; // 0x103022a
+ field public static final int TextAppearance_Material_Widget_PopupMenu_Small = 16974379; // 0x103022b
+ field public static final int TextAppearance_Material_Widget_TabWidget = 16974380; // 0x103022c
+ field public static final int TextAppearance_Material_Widget_TextView = 16974381; // 0x103022d
+ field public static final int TextAppearance_Material_Widget_TextView_PopupMenu = 16974382; // 0x103022e
+ field public static final int TextAppearance_Material_Widget_TextView_SpinnerItem = 16974383; // 0x103022f
+ field public static final int TextAppearance_Material_WindowTitle = 16974361; // 0x1030219
field public static final int TextAppearance_Medium = 16973892; // 0x1030044
field public static final int TextAppearance_Medium_Inverse = 16973893; // 0x1030045
- field public static final int TextAppearance_Quantum = 16974348; // 0x103020c
- field public static final int TextAppearance_Quantum_Body1 = 16974546; // 0x10302d2
- field public static final int TextAppearance_Quantum_Body2 = 16974545; // 0x10302d1
- field public static final int TextAppearance_Quantum_Button = 16974549; // 0x10302d5
- field public static final int TextAppearance_Quantum_Caption = 16974547; // 0x10302d3
- field public static final int TextAppearance_Quantum_DialogWindowTitle = 16974349; // 0x103020d
- field public static final int TextAppearance_Quantum_Display1 = 16974541; // 0x10302cd
- field public static final int TextAppearance_Quantum_Display2 = 16974540; // 0x10302cc
- field public static final int TextAppearance_Quantum_Display3 = 16974539; // 0x10302cb
- field public static final int TextAppearance_Quantum_Display4 = 16974538; // 0x10302ca
- field public static final int TextAppearance_Quantum_Headline = 16974542; // 0x10302ce
- field public static final int TextAppearance_Quantum_Inverse = 16974350; // 0x103020e
- field public static final int TextAppearance_Quantum_Large = 16974351; // 0x103020f
- field public static final int TextAppearance_Quantum_Large_Inverse = 16974352; // 0x1030210
- field public static final int TextAppearance_Quantum_Medium = 16974353; // 0x1030211
- field public static final int TextAppearance_Quantum_Medium_Inverse = 16974354; // 0x1030212
- field public static final int TextAppearance_Quantum_Menu = 16974548; // 0x10302d4
- field public static final int TextAppearance_Quantum_SearchResult_Subtitle = 16974355; // 0x1030213
- field public static final int TextAppearance_Quantum_SearchResult_Title = 16974356; // 0x1030214
- field public static final int TextAppearance_Quantum_Small = 16974357; // 0x1030215
- field public static final int TextAppearance_Quantum_Small_Inverse = 16974358; // 0x1030216
- field public static final int TextAppearance_Quantum_Subhead = 16974544; // 0x10302d0
- field public static final int TextAppearance_Quantum_Title = 16974543; // 0x10302cf
- field public static final int TextAppearance_Quantum_Widget = 16974360; // 0x1030218
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Menu = 16974361; // 0x1030219
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle = 16974362; // 0x103021a
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle_Inverse = 16974363; // 0x103021b
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Title = 16974364; // 0x103021c
- field public static final int TextAppearance_Quantum_Widget_ActionBar_Title_Inverse = 16974365; // 0x103021d
- field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle = 16974366; // 0x103021e
- field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle_Inverse = 16974367; // 0x103021f
- field public static final int TextAppearance_Quantum_Widget_ActionMode_Title = 16974368; // 0x1030220
- field public static final int TextAppearance_Quantum_Widget_ActionMode_Title_Inverse = 16974369; // 0x1030221
- field public static final int TextAppearance_Quantum_Widget_Button = 16974370; // 0x1030222
- field public static final int TextAppearance_Quantum_Widget_DropDownHint = 16974371; // 0x1030223
- field public static final int TextAppearance_Quantum_Widget_DropDownItem = 16974372; // 0x1030224
- field public static final int TextAppearance_Quantum_Widget_EditText = 16974373; // 0x1030225
- field public static final int TextAppearance_Quantum_Widget_IconMenu_Item = 16974374; // 0x1030226
- field public static final int TextAppearance_Quantum_Widget_PopupMenu = 16974375; // 0x1030227
- field public static final int TextAppearance_Quantum_Widget_PopupMenu_Large = 16974376; // 0x1030228
- field public static final int TextAppearance_Quantum_Widget_PopupMenu_Small = 16974377; // 0x1030229
- field public static final int TextAppearance_Quantum_Widget_TabWidget = 16974378; // 0x103022a
- field public static final int TextAppearance_Quantum_Widget_TextView = 16974379; // 0x103022b
- field public static final int TextAppearance_Quantum_Widget_TextView_PopupMenu = 16974380; // 0x103022c
- field public static final int TextAppearance_Quantum_Widget_TextView_SpinnerItem = 16974381; // 0x103022d
- field public static final int TextAppearance_Quantum_WindowTitle = 16974359; // 0x1030217
field public static final int TextAppearance_Small = 16973894; // 0x1030046
field public static final int TextAppearance_Small_Inverse = 16973895; // 0x1030047
field public static final int TextAppearance_StatusBar_EventContent = 16973927; // 0x1030067
@@ -1936,12 +1956,12 @@
field public static final int TextAppearance_Widget_TextView_SpinnerItem = 16973906; // 0x1030052
field public static final int TextAppearance_WindowTitle = 16973907; // 0x1030053
field public static final int Theme = 16973829; // 0x1030005
- field public static final int ThemeOverlay = 16974412; // 0x103024c
- field public static final int ThemeOverlay_Quantum = 16974413; // 0x103024d
- field public static final int ThemeOverlay_Quantum_ActionBar = 16974414; // 0x103024e
- field public static final int ThemeOverlay_Quantum_Dark = 16974416; // 0x1030250
- field public static final int ThemeOverlay_Quantum_Dark_ActionBar = 16974417; // 0x1030251
- field public static final int ThemeOverlay_Quantum_Light = 16974415; // 0x103024f
+ field public static final int ThemeOverlay = 16974416; // 0x1030250
+ field public static final int ThemeOverlay_Material = 16974417; // 0x1030251
+ field public static final int ThemeOverlay_Material_ActionBar = 16974418; // 0x1030252
+ field public static final int ThemeOverlay_Material_Dark = 16974420; // 0x1030254
+ field public static final int ThemeOverlay_Material_Dark_ActionBar = 16974421; // 0x1030255
+ field public static final int ThemeOverlay_Material_Light = 16974419; // 0x1030253
field public static final int Theme_Black = 16973832; // 0x1030008
field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
@@ -1971,6 +1991,7 @@
field public static final int Theme_DeviceDefault_NoActionBar_Overscan = 16974303; // 0x10301df
field public static final int Theme_DeviceDefault_NoActionBar_TranslucentDecor = 16974307; // 0x10301e3
field public static final int Theme_DeviceDefault_Panel = 16974138; // 0x103013a
+ field public static final int Theme_DeviceDefault_Settings = 16974384; // 0x1030230
field public static final int Theme_DeviceDefault_Wallpaper = 16974140; // 0x103013c
field public static final int Theme_DeviceDefault_Wallpaper_NoTitleBar = 16974141; // 0x103013d
field public static final int Theme_Dialog = 16973835; // 0x103000b
@@ -2008,41 +2029,42 @@
field public static final int Theme_Light_NoTitleBar_Fullscreen = 16973838; // 0x103000e
field public static final int Theme_Light_Panel = 16973914; // 0x103005a
field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
+ field public static final int Theme_Material = 16974385; // 0x1030231
+ field public static final int Theme_Material_Dialog = 16974386; // 0x1030232
+ field public static final int Theme_Material_DialogWhenLarge = 16974390; // 0x1030236
+ field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974391; // 0x1030237
+ field public static final int Theme_Material_Dialog_MinWidth = 16974387; // 0x1030233
+ field public static final int Theme_Material_Dialog_NoActionBar = 16974388; // 0x1030234
+ field public static final int Theme_Material_Dialog_NoActionBar_MinWidth = 16974389; // 0x1030235
+ field public static final int Theme_Material_InputMethod = 16974392; // 0x1030238
+ field public static final int Theme_Material_Light = 16974402; // 0x1030242
+ field public static final int Theme_Material_Light_DarkActionBar = 16974403; // 0x1030243
+ field public static final int Theme_Material_Light_Dialog = 16974404; // 0x1030244
+ field public static final int Theme_Material_Light_DialogWhenLarge = 16974408; // 0x1030248
+ field public static final int Theme_Material_Light_DialogWhenLarge_NoActionBar = 16974409; // 0x1030249
+ field public static final int Theme_Material_Light_Dialog_MinWidth = 16974405; // 0x1030245
+ field public static final int Theme_Material_Light_Dialog_NoActionBar = 16974406; // 0x1030246
+ field public static final int Theme_Material_Light_Dialog_NoActionBar_MinWidth = 16974407; // 0x1030247
+ field public static final int Theme_Material_Light_NoActionBar = 16974410; // 0x103024a
+ field public static final int Theme_Material_Light_NoActionBar_Fullscreen = 16974411; // 0x103024b
+ field public static final int Theme_Material_Light_NoActionBar_Overscan = 16974412; // 0x103024c
+ field public static final int Theme_Material_Light_NoActionBar_TranslucentDecor = 16974413; // 0x103024d
+ field public static final int Theme_Material_Light_Panel = 16974414; // 0x103024e
+ field public static final int Theme_Material_Light_Voice = 16974415; // 0x103024f
+ field public static final int Theme_Material_NoActionBar = 16974393; // 0x1030239
+ field public static final int Theme_Material_NoActionBar_Fullscreen = 16974394; // 0x103023a
+ field public static final int Theme_Material_NoActionBar_Overscan = 16974395; // 0x103023b
+ field public static final int Theme_Material_NoActionBar_TranslucentDecor = 16974396; // 0x103023c
+ field public static final int Theme_Material_Panel = 16974397; // 0x103023d
+ field public static final int Theme_Material_Settings = 16974398; // 0x103023e
+ field public static final int Theme_Material_Voice = 16974399; // 0x103023f
+ field public static final int Theme_Material_Wallpaper = 16974400; // 0x1030240
+ field public static final int Theme_Material_Wallpaper_NoTitleBar = 16974401; // 0x1030241
field public static final int Theme_NoDisplay = 16973909; // 0x1030055
field public static final int Theme_NoTitleBar = 16973830; // 0x1030006
field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
field public static final int Theme_NoTitleBar_OverlayActionModes = 16973930; // 0x103006a
field public static final int Theme_Panel = 16973913; // 0x1030059
- field public static final int Theme_Quantum = 16974382; // 0x103022e
- field public static final int Theme_Quantum_Dialog = 16974383; // 0x103022f
- field public static final int Theme_Quantum_DialogWhenLarge = 16974387; // 0x1030233
- field public static final int Theme_Quantum_DialogWhenLarge_NoActionBar = 16974388; // 0x1030234
- field public static final int Theme_Quantum_Dialog_MinWidth = 16974384; // 0x1030230
- field public static final int Theme_Quantum_Dialog_NoActionBar = 16974385; // 0x1030231
- field public static final int Theme_Quantum_Dialog_NoActionBar_MinWidth = 16974386; // 0x1030232
- field public static final int Theme_Quantum_InputMethod = 16974389; // 0x1030235
- field public static final int Theme_Quantum_Light = 16974398; // 0x103023e
- field public static final int Theme_Quantum_Light_DarkActionBar = 16974399; // 0x103023f
- field public static final int Theme_Quantum_Light_Dialog = 16974400; // 0x1030240
- field public static final int Theme_Quantum_Light_DialogWhenLarge = 16974404; // 0x1030244
- field public static final int Theme_Quantum_Light_DialogWhenLarge_NoActionBar = 16974405; // 0x1030245
- field public static final int Theme_Quantum_Light_Dialog_MinWidth = 16974401; // 0x1030241
- field public static final int Theme_Quantum_Light_Dialog_NoActionBar = 16974402; // 0x1030242
- field public static final int Theme_Quantum_Light_Dialog_NoActionBar_MinWidth = 16974403; // 0x1030243
- field public static final int Theme_Quantum_Light_NoActionBar = 16974406; // 0x1030246
- field public static final int Theme_Quantum_Light_NoActionBar_Fullscreen = 16974407; // 0x1030247
- field public static final int Theme_Quantum_Light_NoActionBar_Overscan = 16974408; // 0x1030248
- field public static final int Theme_Quantum_Light_NoActionBar_TranslucentDecor = 16974409; // 0x1030249
- field public static final int Theme_Quantum_Light_Panel = 16974410; // 0x103024a
- field public static final int Theme_Quantum_Light_Voice = 16974411; // 0x103024b
- field public static final int Theme_Quantum_NoActionBar = 16974390; // 0x1030236
- field public static final int Theme_Quantum_NoActionBar_Fullscreen = 16974391; // 0x1030237
- field public static final int Theme_Quantum_NoActionBar_Overscan = 16974392; // 0x1030238
- field public static final int Theme_Quantum_NoActionBar_TranslucentDecor = 16974393; // 0x1030239
- field public static final int Theme_Quantum_Panel = 16974394; // 0x103023a
- field public static final int Theme_Quantum_Voice = 16974395; // 0x103023b
- field public static final int Theme_Quantum_Wallpaper = 16974396; // 0x103023c
- field public static final int Theme_Quantum_Wallpaper_NoTitleBar = 16974397; // 0x103023d
field public static final int Theme_Translucent = 16973839; // 0x103000f
field public static final int Theme_Translucent_NoTitleBar = 16973840; // 0x1030010
field public static final int Theme_Translucent_NoTitleBar_Fullscreen = 16973841; // 0x1030011
@@ -2099,7 +2121,7 @@
field public static final int Widget_DeviceDefault_DropDownItem_Spinner = 16974178; // 0x1030162
field public static final int Widget_DeviceDefault_EditText = 16974154; // 0x103014a
field public static final int Widget_DeviceDefault_ExpandableListView = 16974155; // 0x103014b
- field public static final int Widget_DeviceDefault_FastScroll = 16974344; // 0x1030208
+ field public static final int Widget_DeviceDefault_FastScroll = 16974346; // 0x103020a
field public static final int Widget_DeviceDefault_GridView = 16974156; // 0x103014c
field public static final int Widget_DeviceDefault_HorizontalScrollView = 16974171; // 0x103015b
field public static final int Widget_DeviceDefault_ImageButton = 16974157; // 0x103014d
@@ -2133,7 +2155,7 @@
field public static final int Widget_DeviceDefault_Light_DropDownItem_Spinner = 16974233; // 0x1030199
field public static final int Widget_DeviceDefault_Light_EditText = 16974206; // 0x103017e
field public static final int Widget_DeviceDefault_Light_ExpandableListView = 16974207; // 0x103017f
- field public static final int Widget_DeviceDefault_Light_FastScroll = 16974346; // 0x103020a
+ field public static final int Widget_DeviceDefault_Light_FastScroll = 16974348; // 0x103020c
field public static final int Widget_DeviceDefault_Light_GridView = 16974208; // 0x1030180
field public static final int Widget_DeviceDefault_Light_HorizontalScrollView = 16974226; // 0x1030192
field public static final int Widget_DeviceDefault_Light_ImageButton = 16974209; // 0x1030181
@@ -2157,7 +2179,7 @@
field public static final int Widget_DeviceDefault_Light_ScrollView = 16974225; // 0x1030191
field public static final int Widget_DeviceDefault_Light_SeekBar = 16974220; // 0x103018c
field public static final int Widget_DeviceDefault_Light_Spinner = 16974227; // 0x1030193
- field public static final int Widget_DeviceDefault_Light_StackView = 16974347; // 0x103020b
+ field public static final int Widget_DeviceDefault_Light_StackView = 16974349; // 0x103020d
field public static final int Widget_DeviceDefault_Light_Tab = 16974237; // 0x103019d
field public static final int Widget_DeviceDefault_Light_TabWidget = 16974229; // 0x1030195
field public static final int Widget_DeviceDefault_Light_TextView = 16974202; // 0x103017a
@@ -2181,7 +2203,7 @@
field public static final int Widget_DeviceDefault_ScrollView = 16974170; // 0x103015a
field public static final int Widget_DeviceDefault_SeekBar = 16974165; // 0x1030155
field public static final int Widget_DeviceDefault_Spinner = 16974172; // 0x103015c
- field public static final int Widget_DeviceDefault_StackView = 16974345; // 0x1030209
+ field public static final int Widget_DeviceDefault_StackView = 16974347; // 0x103020b
field public static final int Widget_DeviceDefault_Tab = 16974189; // 0x103016d
field public static final int Widget_DeviceDefault_TabWidget = 16974174; // 0x103015e
field public static final int Widget_DeviceDefault_TextView = 16974150; // 0x1030146
@@ -2224,7 +2246,7 @@
field public static final int Widget_Holo_DropDownItem_Spinner = 16973995; // 0x10300ab
field public static final int Widget_Holo_EditText = 16973971; // 0x1030093
field public static final int Widget_Holo_ExpandableListView = 16973972; // 0x1030094
- field public static final int Widget_Holo_FastScroll = 16974339; // 0x1030203
+ field public static final int Widget_Holo_FastScroll = 16974341; // 0x1030205
field public static final int Widget_Holo_GridView = 16973973; // 0x1030095
field public static final int Widget_Holo_HorizontalScrollView = 16973988; // 0x10300a4
field public static final int Widget_Holo_ImageButton = 16973974; // 0x1030096
@@ -2245,7 +2267,7 @@
field public static final int Widget_Holo_Light_ActionMode_Inverse = 16974119; // 0x1030127
field public static final int Widget_Holo_Light_AutoCompleteTextView = 16974011; // 0x10300bb
field public static final int Widget_Holo_Light_Button = 16974006; // 0x10300b6
- field public static final int Widget_Holo_Light_Button_Borderless = 16974341; // 0x1030205
+ field public static final int Widget_Holo_Light_Button_Borderless = 16974343; // 0x1030207
field public static final int Widget_Holo_Light_Button_Borderless_Small = 16974107; // 0x103011b
field public static final int Widget_Holo_Light_Button_Inset = 16974008; // 0x10300b8
field public static final int Widget_Holo_Light_Button_Small = 16974007; // 0x10300b7
@@ -2259,7 +2281,7 @@
field public static final int Widget_Holo_Light_DropDownItem_Spinner = 16974041; // 0x10300d9
field public static final int Widget_Holo_Light_EditText = 16974014; // 0x10300be
field public static final int Widget_Holo_Light_ExpandableListView = 16974015; // 0x10300bf
- field public static final int Widget_Holo_Light_FastScroll = 16974342; // 0x1030206
+ field public static final int Widget_Holo_Light_FastScroll = 16974344; // 0x1030208
field public static final int Widget_Holo_Light_GridView = 16974016; // 0x10300c0
field public static final int Widget_Holo_Light_HorizontalScrollView = 16974034; // 0x10300d2
field public static final int Widget_Holo_Light_ImageButton = 16974017; // 0x10300c1
@@ -2283,7 +2305,7 @@
field public static final int Widget_Holo_Light_ScrollView = 16974033; // 0x10300d1
field public static final int Widget_Holo_Light_SeekBar = 16974028; // 0x10300cc
field public static final int Widget_Holo_Light_Spinner = 16974035; // 0x10300d3
- field public static final int Widget_Holo_Light_StackView = 16974343; // 0x1030207
+ field public static final int Widget_Holo_Light_StackView = 16974345; // 0x1030209
field public static final int Widget_Holo_Light_Tab = 16974052; // 0x10300e4
field public static final int Widget_Holo_Light_TabWidget = 16974037; // 0x10300d5
field public static final int Widget_Holo_Light_TextView = 16974010; // 0x10300ba
@@ -2307,7 +2329,7 @@
field public static final int Widget_Holo_ScrollView = 16973987; // 0x10300a3
field public static final int Widget_Holo_SeekBar = 16973982; // 0x103009e
field public static final int Widget_Holo_Spinner = 16973989; // 0x10300a5
- field public static final int Widget_Holo_StackView = 16974340; // 0x1030204
+ field public static final int Widget_Holo_StackView = 16974342; // 0x1030206
field public static final int Widget_Holo_Tab = 16974051; // 0x10300e3
field public static final int Widget_Holo_TabWidget = 16973991; // 0x10300a7
field public static final int Widget_Holo_TextView = 16973967; // 0x103008f
@@ -2322,6 +2344,128 @@
field public static final int Widget_ListView_DropDown = 16973872; // 0x1030030
field public static final int Widget_ListView_Menu = 16973873; // 0x1030031
field public static final int Widget_ListView_White = 16973871; // 0x103002f
+ field public static final int Widget_Material = 16974422; // 0x1030256
+ field public static final int Widget_Material_ActionBar = 16974423; // 0x1030257
+ field public static final int Widget_Material_ActionBar_Solid = 16974424; // 0x1030258
+ field public static final int Widget_Material_ActionBar_TabBar = 16974425; // 0x1030259
+ field public static final int Widget_Material_ActionBar_TabText = 16974426; // 0x103025a
+ field public static final int Widget_Material_ActionBar_TabView = 16974427; // 0x103025b
+ field public static final int Widget_Material_ActionButton = 16974428; // 0x103025c
+ field public static final int Widget_Material_ActionButton_CloseMode = 16974429; // 0x103025d
+ field public static final int Widget_Material_ActionButton_Overflow = 16974430; // 0x103025e
+ field public static final int Widget_Material_ActionMode = 16974431; // 0x103025f
+ field public static final int Widget_Material_AutoCompleteTextView = 16974432; // 0x1030260
+ field public static final int Widget_Material_Button = 16974433; // 0x1030261
+ field public static final int Widget_Material_ButtonBar = 16974439; // 0x1030267
+ field public static final int Widget_Material_ButtonBar_AlertDialog = 16974440; // 0x1030268
+ field public static final int Widget_Material_Button_Borderless = 16974434; // 0x1030262
+ field public static final int Widget_Material_Button_Borderless_Small = 16974435; // 0x1030263
+ field public static final int Widget_Material_Button_Inset = 16974436; // 0x1030264
+ field public static final int Widget_Material_Button_Small = 16974437; // 0x1030265
+ field public static final int Widget_Material_Button_Toggle = 16974438; // 0x1030266
+ field public static final int Widget_Material_CalendarView = 16974441; // 0x1030269
+ field public static final int Widget_Material_CheckedTextView = 16974442; // 0x103026a
+ field public static final int Widget_Material_CompoundButton_CheckBox = 16974443; // 0x103026b
+ field public static final int Widget_Material_CompoundButton_RadioButton = 16974444; // 0x103026c
+ field public static final int Widget_Material_CompoundButton_Star = 16974445; // 0x103026d
+ field public static final int Widget_Material_DatePicker = 16974446; // 0x103026e
+ field public static final int Widget_Material_DropDownItem = 16974447; // 0x103026f
+ field public static final int Widget_Material_DropDownItem_Spinner = 16974448; // 0x1030270
+ field public static final int Widget_Material_EditText = 16974449; // 0x1030271
+ field public static final int Widget_Material_ExpandableListView = 16974450; // 0x1030272
+ field public static final int Widget_Material_FastScroll = 16974451; // 0x1030273
+ field public static final int Widget_Material_GridView = 16974452; // 0x1030274
+ field public static final int Widget_Material_HorizontalScrollView = 16974453; // 0x1030275
+ field public static final int Widget_Material_ImageButton = 16974454; // 0x1030276
+ field public static final int Widget_Material_Light = 16974483; // 0x1030293
+ field public static final int Widget_Material_Light_ActionBar = 16974484; // 0x1030294
+ field public static final int Widget_Material_Light_ActionBar_Solid = 16974485; // 0x1030295
+ field public static final int Widget_Material_Light_ActionBar_TabBar = 16974486; // 0x1030296
+ field public static final int Widget_Material_Light_ActionBar_TabText = 16974487; // 0x1030297
+ field public static final int Widget_Material_Light_ActionBar_TabView = 16974488; // 0x1030298
+ field public static final int Widget_Material_Light_ActionButton = 16974489; // 0x1030299
+ field public static final int Widget_Material_Light_ActionButton_CloseMode = 16974490; // 0x103029a
+ field public static final int Widget_Material_Light_ActionButton_Overflow = 16974491; // 0x103029b
+ field public static final int Widget_Material_Light_ActionMode = 16974492; // 0x103029c
+ field public static final int Widget_Material_Light_AutoCompleteTextView = 16974493; // 0x103029d
+ field public static final int Widget_Material_Light_Button = 16974494; // 0x103029e
+ field public static final int Widget_Material_Light_ButtonBar = 16974500; // 0x10302a4
+ field public static final int Widget_Material_Light_ButtonBar_AlertDialog = 16974501; // 0x10302a5
+ field public static final int Widget_Material_Light_Button_Borderless = 16974495; // 0x103029f
+ field public static final int Widget_Material_Light_Button_Borderless_Small = 16974496; // 0x10302a0
+ field public static final int Widget_Material_Light_Button_Inset = 16974497; // 0x10302a1
+ field public static final int Widget_Material_Light_Button_Small = 16974498; // 0x10302a2
+ field public static final int Widget_Material_Light_Button_Toggle = 16974499; // 0x10302a3
+ field public static final int Widget_Material_Light_CalendarView = 16974502; // 0x10302a6
+ field public static final int Widget_Material_Light_CheckedTextView = 16974503; // 0x10302a7
+ field public static final int Widget_Material_Light_CompoundButton_CheckBox = 16974504; // 0x10302a8
+ field public static final int Widget_Material_Light_CompoundButton_RadioButton = 16974505; // 0x10302a9
+ field public static final int Widget_Material_Light_CompoundButton_Star = 16974506; // 0x10302aa
+ field public static final int Widget_Material_Light_DropDownItem = 16974507; // 0x10302ab
+ field public static final int Widget_Material_Light_DropDownItem_Spinner = 16974508; // 0x10302ac
+ field public static final int Widget_Material_Light_EditText = 16974509; // 0x10302ad
+ field public static final int Widget_Material_Light_ExpandableListView = 16974510; // 0x10302ae
+ field public static final int Widget_Material_Light_FastScroll = 16974511; // 0x10302af
+ field public static final int Widget_Material_Light_GridView = 16974512; // 0x10302b0
+ field public static final int Widget_Material_Light_HorizontalScrollView = 16974513; // 0x10302b1
+ field public static final int Widget_Material_Light_ImageButton = 16974514; // 0x10302b2
+ field public static final int Widget_Material_Light_ListPopupWindow = 16974515; // 0x10302b3
+ field public static final int Widget_Material_Light_ListView = 16974516; // 0x10302b4
+ field public static final int Widget_Material_Light_ListView_DropDown = 16974517; // 0x10302b5
+ field public static final int Widget_Material_Light_MediaRouteButton = 16974518; // 0x10302b6
+ field public static final int Widget_Material_Light_PopupMenu = 16974519; // 0x10302b7
+ field public static final int Widget_Material_Light_PopupMenu_Overflow = 16974520; // 0x10302b8
+ field public static final int Widget_Material_Light_PopupWindow = 16974521; // 0x10302b9
+ field public static final int Widget_Material_Light_ProgressBar = 16974522; // 0x10302ba
+ field public static final int Widget_Material_Light_ProgressBar_Horizontal = 16974523; // 0x10302bb
+ field public static final int Widget_Material_Light_ProgressBar_Inverse = 16974524; // 0x10302bc
+ field public static final int Widget_Material_Light_ProgressBar_Large = 16974525; // 0x10302bd
+ field public static final int Widget_Material_Light_ProgressBar_Large_Inverse = 16974526; // 0x10302be
+ field public static final int Widget_Material_Light_ProgressBar_Small = 16974527; // 0x10302bf
+ field public static final int Widget_Material_Light_ProgressBar_Small_Inverse = 16974528; // 0x10302c0
+ field public static final int Widget_Material_Light_ProgressBar_Small_Title = 16974529; // 0x10302c1
+ field public static final int Widget_Material_Light_RatingBar = 16974530; // 0x10302c2
+ field public static final int Widget_Material_Light_RatingBar_Indicator = 16974531; // 0x10302c3
+ field public static final int Widget_Material_Light_RatingBar_Small = 16974532; // 0x10302c4
+ field public static final int Widget_Material_Light_ScrollView = 16974533; // 0x10302c5
+ field public static final int Widget_Material_Light_SeekBar = 16974534; // 0x10302c6
+ field public static final int Widget_Material_Light_SegmentedButton = 16974535; // 0x10302c7
+ field public static final int Widget_Material_Light_Spinner = 16974537; // 0x10302c9
+ field public static final int Widget_Material_Light_StackView = 16974536; // 0x10302c8
+ field public static final int Widget_Material_Light_Tab = 16974538; // 0x10302ca
+ field public static final int Widget_Material_Light_TabWidget = 16974539; // 0x10302cb
+ field public static final int Widget_Material_Light_TextView = 16974540; // 0x10302cc
+ field public static final int Widget_Material_Light_TextView_SpinnerItem = 16974541; // 0x10302cd
+ field public static final int Widget_Material_Light_WebTextView = 16974542; // 0x10302ce
+ field public static final int Widget_Material_Light_WebView = 16974543; // 0x10302cf
+ field public static final int Widget_Material_ListPopupWindow = 16974455; // 0x1030277
+ field public static final int Widget_Material_ListView = 16974456; // 0x1030278
+ field public static final int Widget_Material_ListView_DropDown = 16974457; // 0x1030279
+ field public static final int Widget_Material_MediaRouteButton = 16974458; // 0x103027a
+ field public static final int Widget_Material_PopupMenu = 16974459; // 0x103027b
+ field public static final int Widget_Material_PopupMenu_Overflow = 16974460; // 0x103027c
+ field public static final int Widget_Material_PopupWindow = 16974461; // 0x103027d
+ field public static final int Widget_Material_ProgressBar = 16974462; // 0x103027e
+ field public static final int Widget_Material_ProgressBar_Horizontal = 16974463; // 0x103027f
+ field public static final int Widget_Material_ProgressBar_Large = 16974464; // 0x1030280
+ field public static final int Widget_Material_ProgressBar_Small = 16974465; // 0x1030281
+ field public static final int Widget_Material_ProgressBar_Small_Title = 16974466; // 0x1030282
+ field public static final int Widget_Material_RatingBar = 16974467; // 0x1030283
+ field public static final int Widget_Material_RatingBar_Indicator = 16974468; // 0x1030284
+ field public static final int Widget_Material_RatingBar_Small = 16974469; // 0x1030285
+ field public static final int Widget_Material_ScrollView = 16974470; // 0x1030286
+ field public static final int Widget_Material_SeekBar = 16974471; // 0x1030287
+ field public static final int Widget_Material_SegmentedButton = 16974472; // 0x1030288
+ field public static final int Widget_Material_Spinner = 16974474; // 0x103028a
+ field public static final int Widget_Material_StackView = 16974473; // 0x1030289
+ field public static final int Widget_Material_Tab = 16974475; // 0x103028b
+ field public static final int Widget_Material_TabWidget = 16974476; // 0x103028c
+ field public static final int Widget_Material_TextView = 16974477; // 0x103028d
+ field public static final int Widget_Material_TextView_SpinnerItem = 16974478; // 0x103028e
+ field public static final int Widget_Material_Toolbar = 16974479; // 0x103028f
+ field public static final int Widget_Material_Toolbar_Button_Navigation = 16974480; // 0x1030290
+ field public static final int Widget_Material_WebTextView = 16974481; // 0x1030291
+ field public static final int Widget_Material_WebView = 16974482; // 0x1030292
field public static final int Widget_PopupMenu = 16973958; // 0x1030086
field public static final int Widget_PopupWindow = 16973878; // 0x1030036
field public static final int Widget_ProgressBar = 16973852; // 0x103001c
@@ -2331,126 +2475,6 @@
field public static final int Widget_ProgressBar_Large_Inverse = 16973916; // 0x103005c
field public static final int Widget_ProgressBar_Small = 16973854; // 0x103001e
field public static final int Widget_ProgressBar_Small_Inverse = 16973917; // 0x103005d
- field public static final int Widget_Quantum = 16974418; // 0x1030252
- field public static final int Widget_Quantum_ActionBar = 16974419; // 0x1030253
- field public static final int Widget_Quantum_ActionBar_Solid = 16974420; // 0x1030254
- field public static final int Widget_Quantum_ActionBar_TabBar = 16974421; // 0x1030255
- field public static final int Widget_Quantum_ActionBar_TabText = 16974422; // 0x1030256
- field public static final int Widget_Quantum_ActionBar_TabView = 16974423; // 0x1030257
- field public static final int Widget_Quantum_ActionButton = 16974424; // 0x1030258
- field public static final int Widget_Quantum_ActionButton_CloseMode = 16974425; // 0x1030259
- field public static final int Widget_Quantum_ActionButton_Overflow = 16974426; // 0x103025a
- field public static final int Widget_Quantum_ActionMode = 16974427; // 0x103025b
- field public static final int Widget_Quantum_AutoCompleteTextView = 16974428; // 0x103025c
- field public static final int Widget_Quantum_Button = 16974429; // 0x103025d
- field public static final int Widget_Quantum_ButtonBar = 16974435; // 0x1030263
- field public static final int Widget_Quantum_ButtonBar_AlertDialog = 16974436; // 0x1030264
- field public static final int Widget_Quantum_Button_Borderless = 16974430; // 0x103025e
- field public static final int Widget_Quantum_Button_Borderless_Small = 16974431; // 0x103025f
- field public static final int Widget_Quantum_Button_Inset = 16974432; // 0x1030260
- field public static final int Widget_Quantum_Button_Small = 16974433; // 0x1030261
- field public static final int Widget_Quantum_Button_Toggle = 16974434; // 0x1030262
- field public static final int Widget_Quantum_CalendarView = 16974437; // 0x1030265
- field public static final int Widget_Quantum_CheckedTextView = 16974438; // 0x1030266
- field public static final int Widget_Quantum_CompoundButton_CheckBox = 16974439; // 0x1030267
- field public static final int Widget_Quantum_CompoundButton_RadioButton = 16974440; // 0x1030268
- field public static final int Widget_Quantum_CompoundButton_Star = 16974441; // 0x1030269
- field public static final int Widget_Quantum_DatePicker = 16974442; // 0x103026a
- field public static final int Widget_Quantum_DropDownItem = 16974443; // 0x103026b
- field public static final int Widget_Quantum_DropDownItem_Spinner = 16974444; // 0x103026c
- field public static final int Widget_Quantum_EditText = 16974445; // 0x103026d
- field public static final int Widget_Quantum_ExpandableListView = 16974446; // 0x103026e
- field public static final int Widget_Quantum_FastScroll = 16974447; // 0x103026f
- field public static final int Widget_Quantum_GridView = 16974448; // 0x1030270
- field public static final int Widget_Quantum_HorizontalScrollView = 16974449; // 0x1030271
- field public static final int Widget_Quantum_ImageButton = 16974450; // 0x1030272
- field public static final int Widget_Quantum_Light = 16974477; // 0x103028d
- field public static final int Widget_Quantum_Light_ActionBar = 16974478; // 0x103028e
- field public static final int Widget_Quantum_Light_ActionBar_Solid = 16974479; // 0x103028f
- field public static final int Widget_Quantum_Light_ActionBar_TabBar = 16974480; // 0x1030290
- field public static final int Widget_Quantum_Light_ActionBar_TabText = 16974481; // 0x1030291
- field public static final int Widget_Quantum_Light_ActionBar_TabView = 16974482; // 0x1030292
- field public static final int Widget_Quantum_Light_ActionButton = 16974483; // 0x1030293
- field public static final int Widget_Quantum_Light_ActionButton_CloseMode = 16974484; // 0x1030294
- field public static final int Widget_Quantum_Light_ActionButton_Overflow = 16974485; // 0x1030295
- field public static final int Widget_Quantum_Light_ActionMode = 16974486; // 0x1030296
- field public static final int Widget_Quantum_Light_AutoCompleteTextView = 16974487; // 0x1030297
- field public static final int Widget_Quantum_Light_Button = 16974488; // 0x1030298
- field public static final int Widget_Quantum_Light_ButtonBar = 16974494; // 0x103029e
- field public static final int Widget_Quantum_Light_ButtonBar_AlertDialog = 16974495; // 0x103029f
- field public static final int Widget_Quantum_Light_Button_Borderless = 16974489; // 0x1030299
- field public static final int Widget_Quantum_Light_Button_Borderless_Small = 16974490; // 0x103029a
- field public static final int Widget_Quantum_Light_Button_Inset = 16974491; // 0x103029b
- field public static final int Widget_Quantum_Light_Button_Small = 16974492; // 0x103029c
- field public static final int Widget_Quantum_Light_Button_Toggle = 16974493; // 0x103029d
- field public static final int Widget_Quantum_Light_CalendarView = 16974496; // 0x10302a0
- field public static final int Widget_Quantum_Light_CheckedTextView = 16974497; // 0x10302a1
- field public static final int Widget_Quantum_Light_CompoundButton_CheckBox = 16974498; // 0x10302a2
- field public static final int Widget_Quantum_Light_CompoundButton_RadioButton = 16974499; // 0x10302a3
- field public static final int Widget_Quantum_Light_CompoundButton_Star = 16974500; // 0x10302a4
- field public static final int Widget_Quantum_Light_DropDownItem = 16974501; // 0x10302a5
- field public static final int Widget_Quantum_Light_DropDownItem_Spinner = 16974502; // 0x10302a6
- field public static final int Widget_Quantum_Light_EditText = 16974503; // 0x10302a7
- field public static final int Widget_Quantum_Light_ExpandableListView = 16974504; // 0x10302a8
- field public static final int Widget_Quantum_Light_FastScroll = 16974505; // 0x10302a9
- field public static final int Widget_Quantum_Light_GridView = 16974506; // 0x10302aa
- field public static final int Widget_Quantum_Light_HorizontalScrollView = 16974507; // 0x10302ab
- field public static final int Widget_Quantum_Light_ImageButton = 16974508; // 0x10302ac
- field public static final int Widget_Quantum_Light_ListPopupWindow = 16974509; // 0x10302ad
- field public static final int Widget_Quantum_Light_ListView = 16974510; // 0x10302ae
- field public static final int Widget_Quantum_Light_ListView_DropDown = 16974511; // 0x10302af
- field public static final int Widget_Quantum_Light_MediaRouteButton = 16974512; // 0x10302b0
- field public static final int Widget_Quantum_Light_PopupMenu = 16974513; // 0x10302b1
- field public static final int Widget_Quantum_Light_PopupMenu_Overflow = 16974514; // 0x10302b2
- field public static final int Widget_Quantum_Light_PopupWindow = 16974515; // 0x10302b3
- field public static final int Widget_Quantum_Light_ProgressBar = 16974516; // 0x10302b4
- field public static final int Widget_Quantum_Light_ProgressBar_Horizontal = 16974517; // 0x10302b5
- field public static final int Widget_Quantum_Light_ProgressBar_Inverse = 16974518; // 0x10302b6
- field public static final int Widget_Quantum_Light_ProgressBar_Large = 16974519; // 0x10302b7
- field public static final int Widget_Quantum_Light_ProgressBar_Large_Inverse = 16974520; // 0x10302b8
- field public static final int Widget_Quantum_Light_ProgressBar_Small = 16974521; // 0x10302b9
- field public static final int Widget_Quantum_Light_ProgressBar_Small_Inverse = 16974522; // 0x10302ba
- field public static final int Widget_Quantum_Light_ProgressBar_Small_Title = 16974523; // 0x10302bb
- field public static final int Widget_Quantum_Light_RatingBar = 16974524; // 0x10302bc
- field public static final int Widget_Quantum_Light_RatingBar_Indicator = 16974525; // 0x10302bd
- field public static final int Widget_Quantum_Light_RatingBar_Small = 16974526; // 0x10302be
- field public static final int Widget_Quantum_Light_ScrollView = 16974527; // 0x10302bf
- field public static final int Widget_Quantum_Light_SeekBar = 16974528; // 0x10302c0
- field public static final int Widget_Quantum_Light_SegmentedButton = 16974529; // 0x10302c1
- field public static final int Widget_Quantum_Light_Spinner = 16974531; // 0x10302c3
- field public static final int Widget_Quantum_Light_StackView = 16974530; // 0x10302c2
- field public static final int Widget_Quantum_Light_Tab = 16974532; // 0x10302c4
- field public static final int Widget_Quantum_Light_TabWidget = 16974533; // 0x10302c5
- field public static final int Widget_Quantum_Light_TextView = 16974534; // 0x10302c6
- field public static final int Widget_Quantum_Light_TextView_SpinnerItem = 16974535; // 0x10302c7
- field public static final int Widget_Quantum_Light_WebTextView = 16974536; // 0x10302c8
- field public static final int Widget_Quantum_Light_WebView = 16974537; // 0x10302c9
- field public static final int Widget_Quantum_ListPopupWindow = 16974451; // 0x1030273
- field public static final int Widget_Quantum_ListView = 16974452; // 0x1030274
- field public static final int Widget_Quantum_ListView_DropDown = 16974453; // 0x1030275
- field public static final int Widget_Quantum_MediaRouteButton = 16974454; // 0x1030276
- field public static final int Widget_Quantum_PopupMenu = 16974455; // 0x1030277
- field public static final int Widget_Quantum_PopupMenu_Overflow = 16974456; // 0x1030278
- field public static final int Widget_Quantum_PopupWindow = 16974457; // 0x1030279
- field public static final int Widget_Quantum_ProgressBar = 16974458; // 0x103027a
- field public static final int Widget_Quantum_ProgressBar_Horizontal = 16974459; // 0x103027b
- field public static final int Widget_Quantum_ProgressBar_Large = 16974460; // 0x103027c
- field public static final int Widget_Quantum_ProgressBar_Small = 16974461; // 0x103027d
- field public static final int Widget_Quantum_ProgressBar_Small_Title = 16974462; // 0x103027e
- field public static final int Widget_Quantum_RatingBar = 16974463; // 0x103027f
- field public static final int Widget_Quantum_RatingBar_Indicator = 16974464; // 0x1030280
- field public static final int Widget_Quantum_RatingBar_Small = 16974465; // 0x1030281
- field public static final int Widget_Quantum_ScrollView = 16974466; // 0x1030282
- field public static final int Widget_Quantum_SeekBar = 16974467; // 0x1030283
- field public static final int Widget_Quantum_SegmentedButton = 16974468; // 0x1030284
- field public static final int Widget_Quantum_Spinner = 16974470; // 0x1030286
- field public static final int Widget_Quantum_StackView = 16974469; // 0x1030285
- field public static final int Widget_Quantum_Tab = 16974471; // 0x1030287
- field public static final int Widget_Quantum_TabWidget = 16974472; // 0x1030288
- field public static final int Widget_Quantum_TextView = 16974473; // 0x1030289
- field public static final int Widget_Quantum_TextView_SpinnerItem = 16974474; // 0x103028a
- field public static final int Widget_Quantum_WebTextView = 16974475; // 0x103028b
- field public static final int Widget_Quantum_WebView = 16974476; // 0x103028c
field public static final int Widget_RatingBar = 16973857; // 0x1030021
field public static final int Widget_ScrollView = 16973869; // 0x103002d
field public static final int Widget_SeekBar = 16973856; // 0x1030020
@@ -2461,6 +2485,8 @@
field public static final int Widget_TextView = 16973858; // 0x1030022
field public static final int Widget_TextView_PopupMenu = 16973865; // 0x1030029
field public static final int Widget_TextView_SpinnerItem = 16973866; // 0x103002a
+ field public static final int Widget_Toolbar = 16974339; // 0x1030203
+ field public static final int Widget_Toolbar_Button_Navigation = 16974340; // 0x1030204
field public static final int Widget_WebView = 16973875; // 0x1030033
field public static final int l_resource_pad1 = 16974336; // 0x1030200
field public static final int l_resource_pad10 = 16974327; // 0x10301f7
@@ -3339,6 +3365,7 @@
method public void openContextMenu(android.view.View);
method public void openOptionsMenu();
method public void overridePendingTransition(int, int);
+ method public void postponeEnterTransition();
method public void recreate();
method public void registerForContextMenu(android.view.View);
method public final deprecated void removeDialog(int);
@@ -3394,6 +3421,7 @@
method public deprecated void startManagingCursor(android.database.Cursor);
method public boolean startNextMatchingActivity(android.content.Intent);
method public boolean startNextMatchingActivity(android.content.Intent, android.os.Bundle);
+ method public void startPostponedEnterTransition();
method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
method public void stopLockTask();
method public deprecated void stopManagingCursor(android.database.Cursor);
@@ -4191,6 +4219,9 @@
method public abstract android.app.FragmentTransaction setBreadCrumbTitle(java.lang.CharSequence);
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int);
method public abstract android.app.FragmentTransaction setCustomAnimations(int, int, int, int);
+ method public abstract android.app.FragmentTransaction setCustomTransition(int, int);
+ method public abstract android.app.FragmentTransaction setSharedElement(android.view.View, java.lang.String);
+ method public abstract android.app.FragmentTransaction setSharedElements(android.util.Pair<android.view.View, java.lang.String>...);
method public abstract android.app.FragmentTransaction setTransition(int);
method public abstract android.app.FragmentTransaction setTransitionStyle(int);
method public abstract android.app.FragmentTransaction show(android.app.Fragment);
@@ -4488,6 +4519,7 @@
field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final java.lang.String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
field public static final int PRIORITY_DEFAULT = 0; // 0x0
field public static final int PRIORITY_HIGH = 1; // 0x1
field public static final int PRIORITY_LOW = -1; // 0xffffffff
@@ -4844,6 +4876,9 @@
field public static final int MENU_KEYCODE = 47; // 0x2f
field public static final java.lang.String QUERY = "query";
field public static final java.lang.String SHORTCUT_MIME_TYPE = "vnd.android.cursor.item/vnd.android.search.suggest";
+ field public static final java.lang.String SUGGEST_COLUMN_AUDIO_CHANNEL_CONFIG = "suggest_audio_channel_config";
+ field public static final java.lang.String SUGGEST_COLUMN_CONTENT_TYPE = "suggest_content_type";
+ field public static final java.lang.String SUGGEST_COLUMN_DURATION = "suggest_duration";
field public static final java.lang.String SUGGEST_COLUMN_FLAGS = "suggest_flags";
field public static final java.lang.String SUGGEST_COLUMN_FORMAT = "suggest_format";
field public static final java.lang.String SUGGEST_COLUMN_ICON_1 = "suggest_icon_1";
@@ -4852,13 +4887,22 @@
field public static final java.lang.String SUGGEST_COLUMN_INTENT_DATA = "suggest_intent_data";
field public static final java.lang.String SUGGEST_COLUMN_INTENT_DATA_ID = "suggest_intent_data_id";
field public static final java.lang.String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
+ field public static final java.lang.String SUGGEST_COLUMN_IS_LIVE = "suggest_is_live";
field public static final java.lang.String SUGGEST_COLUMN_LAST_ACCESS_HINT = "suggest_last_access_hint";
+ field public static final java.lang.String SUGGEST_COLUMN_PRODUCTION_YEAR = "suggest_production_year";
+ field public static final java.lang.String SUGGEST_COLUMN_PURCHASE_PRICE = "suggest_purchase_price";
field public static final java.lang.String SUGGEST_COLUMN_QUERY = "suggest_intent_query";
+ field public static final java.lang.String SUGGEST_COLUMN_RATING_SCORE = "suggest_rating_score";
+ field public static final java.lang.String SUGGEST_COLUMN_RATING_STYLE = "suggest_rating_style";
+ field public static final java.lang.String SUGGEST_COLUMN_RENTAL_PRICE = "suggest_rental_price";
+ field public static final java.lang.String SUGGEST_COLUMN_RESULT_CARD_IMAGE = "suggest_result_card_image";
field public static final java.lang.String SUGGEST_COLUMN_SHORTCUT_ID = "suggest_shortcut_id";
field public static final java.lang.String SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING = "suggest_spinner_while_refreshing";
field public static final java.lang.String SUGGEST_COLUMN_TEXT_1 = "suggest_text_1";
field public static final java.lang.String SUGGEST_COLUMN_TEXT_2 = "suggest_text_2";
field public static final java.lang.String SUGGEST_COLUMN_TEXT_2_URL = "suggest_text_2_url";
+ field public static final java.lang.String SUGGEST_COLUMN_VIDEO_HEIGHT = "suggest_video_height";
+ field public static final java.lang.String SUGGEST_COLUMN_VIDEO_WIDTH = "suggest_video_width";
field public static final java.lang.String SUGGEST_MIME_TYPE = "vnd.android.cursor.dir/vnd.android.search.suggest";
field public static final java.lang.String SUGGEST_NEVER_MAKE_SHORTCUT = "_-1";
field public static final java.lang.String SUGGEST_PARAMETER_LIMIT = "limit";
@@ -5172,8 +5216,10 @@
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
+ method public void clearDeviceOwnerApp();
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
+ method public android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
method public android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
@@ -5203,6 +5249,7 @@
method public boolean isApplicationBlocked(android.content.ComponentName, java.lang.String);
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(android.content.ComponentName);
+ method public boolean isMasterVolumeMuted(android.content.ComponentName);
method public boolean isProfileOwnerApp(java.lang.String);
method public void lockNow();
method public void removeActiveAdmin(android.content.ComponentName);
@@ -5216,6 +5263,7 @@
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskComponents(android.content.ComponentName[]) throws java.lang.SecurityException;
+ method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
@@ -5229,6 +5277,7 @@
method public void setPasswordMinimumUpperCase(android.content.ComponentName, int);
method public void setPasswordQuality(android.content.ComponentName, int);
method public void setProfileEnabled(android.content.ComponentName);
+ method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo);
method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public int setStorageEncryption(android.content.ComponentName, boolean);
@@ -5244,8 +5293,8 @@
field public static final int ENCRYPTION_STATUS_UNSUPPORTED = 0; // 0x0
field public static final java.lang.String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
- field public static final java.lang.String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME = "defaultManagedProfileName";
- field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "deviceAdminPackageName";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME = "android.app.extra.defaultManagedProfileName";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.deviceAdminPackageName";
field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.ManagedProfileEmailAddress";
field public static final java.lang.String EXTRA_PROVISIONING_TOKEN = "android.app.extra.token";
field public static int FLAG_MANAGED_CAN_ACCESS_PARENT;
@@ -5352,23 +5401,9 @@
}
-package android.app.maintenance {
+package android.app.job {
- public abstract class IdleService extends android.app.Service {
- ctor public IdleService();
- method public final void finishIdle();
- method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract boolean onIdleStart();
- method public abstract void onIdleStop();
- field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_IDLE_SERVICE";
- field public static final java.lang.String SERVICE_INTERFACE = "android.service.idle.IdleService";
- }
-
-}
-
-package android.app.task {
-
- public class Task implements android.os.Parcelable {
+ public class JobInfo implements android.os.Parcelable {
method public int describeContents();
method public int getBackoffPolicy();
method public android.os.PersistableBundle getExtras();
@@ -5386,55 +5421,55 @@
field public static final android.os.Parcelable.Creator CREATOR;
}
- public static abstract interface Task.BackoffPolicy {
+ public static abstract interface JobInfo.BackoffPolicy {
field public static final int EXPONENTIAL = 1; // 0x1
field public static final int LINEAR = 0; // 0x0
}
- public static final class Task.Builder {
- ctor public Task.Builder(int, android.content.ComponentName);
- method public android.app.task.Task build();
- method public android.app.task.Task.Builder setBackoffCriteria(long, int);
- method public android.app.task.Task.Builder setExtras(android.os.PersistableBundle);
- method public android.app.task.Task.Builder setMinimumLatency(long);
- method public android.app.task.Task.Builder setOverrideDeadline(long);
- method public android.app.task.Task.Builder setPeriodic(long);
- method public android.app.task.Task.Builder setRequiredNetworkCapabilities(int);
- method public android.app.task.Task.Builder setRequiresCharging(boolean);
- method public android.app.task.Task.Builder setRequiresDeviceIdle(boolean);
+ public static final class JobInfo.Builder {
+ ctor public JobInfo.Builder(int, android.content.ComponentName);
+ method public android.app.job.JobInfo build();
+ method public android.app.job.JobInfo.Builder setBackoffCriteria(long, int);
+ method public android.app.job.JobInfo.Builder setExtras(android.os.PersistableBundle);
+ method public android.app.job.JobInfo.Builder setMinimumLatency(long);
+ method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
+ method public android.app.job.JobInfo.Builder setPeriodic(long);
+ method public android.app.job.JobInfo.Builder setRequiredNetworkCapabilities(int);
+ method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
+ method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
}
- public static abstract interface Task.NetworkType {
+ public static abstract interface JobInfo.NetworkType {
field public static final int ANY = 1; // 0x1
field public static final int NONE = 0; // 0x0
field public static final int UNMETERED = 2; // 0x2
}
- public abstract class TaskManager {
- ctor public TaskManager();
- method public abstract void cancel(int);
- method public abstract void cancelAll();
- method public abstract java.util.List<android.app.task.Task> getAllPendingTasks();
- method public abstract int schedule(android.app.task.Task);
- field public static final int RESULT_FAILURE = 0; // 0x0
- field public static final int RESULT_SUCCESS = 1; // 0x1
- }
-
- public class TaskParams implements android.os.Parcelable {
+ public class JobParameters implements android.os.Parcelable {
method public int describeContents();
method public android.os.PersistableBundle getExtras();
- method public int getTaskId();
+ method public int getJobId();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
}
- public abstract class TaskService extends android.app.Service {
- ctor public TaskService();
+ public abstract class JobScheduler {
+ ctor public JobScheduler();
+ method public abstract void cancel(int);
+ method public abstract void cancelAll();
+ method public abstract java.util.List<android.app.job.JobInfo> getAllPendingJobs();
+ method public abstract int schedule(android.app.job.JobInfo);
+ field public static final int RESULT_FAILURE = 0; // 0x0
+ field public static final int RESULT_SUCCESS = 1; // 0x1
+ }
+
+ public abstract class JobService extends android.app.Service {
+ ctor public JobService();
+ method public final void jobFinished(android.app.job.JobParameters, boolean);
method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract boolean onStartTask(android.app.task.TaskParams);
- method public abstract boolean onStopTask(android.app.task.TaskParams);
- method public final void taskFinished(android.app.task.TaskParams, boolean);
- field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_TASK_SERVICE";
+ method public abstract boolean onStartJob(android.app.job.JobParameters);
+ method public abstract boolean onStopJob(android.app.job.JobParameters);
+ field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE";
}
}
@@ -7001,10 +7036,9 @@
field public static final java.lang.String DOWNLOAD_SERVICE = "download";
field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
- field public static final java.lang.String HDMI_CEC_SERVICE = "hdmi_cec";
- field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
+ field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
field public static final java.lang.String LAYOUT_INFLATER_SERVICE = "layout_inflater";
@@ -7026,7 +7060,7 @@
field public static final java.lang.String SEARCH_SERVICE = "search";
field public static final java.lang.String SENSOR_SERVICE = "sensor";
field public static final java.lang.String STORAGE_SERVICE = "storage";
- field public static final java.lang.String TASK_SERVICE = "task";
+ field public static final java.lang.String TELECOMM_SERVICE = "telecomm";
field public static final java.lang.String TELEPHONY_SERVICE = "phone";
field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
field public static final java.lang.String TV_INPUT_SERVICE = "tv_input";
@@ -7397,6 +7431,7 @@
field public static final java.lang.String ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED";
field public static final java.lang.String ACTION_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
field public static final java.lang.String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
+ field public static final java.lang.String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
field public static final java.lang.String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
field public static final java.lang.String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
field public static final java.lang.String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
@@ -7411,7 +7446,6 @@
field public static final java.lang.String ACTION_PASTE = "android.intent.action.PASTE";
field public static final java.lang.String ACTION_PICK = "android.intent.action.PICK";
field public static final java.lang.String ACTION_PICK_ACTIVITY = "android.intent.action.PICK_ACTIVITY";
- field public static final java.lang.String ACTION_PICK_DIRECTORY = "android.intent.action.PICK_DIRECTORY";
field public static final java.lang.String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
field public static final java.lang.String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
field public static final java.lang.String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
@@ -7471,7 +7505,6 @@
field public static final java.lang.String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
field public static final java.lang.String CATEGORY_LE_DESK_DOCK = "android.intent.category.LE_DESK_DOCK";
field public static final java.lang.String CATEGORY_MONKEY = "android.intent.category.MONKEY";
- field public static final java.lang.String CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
field public static final java.lang.String CATEGORY_OPENABLE = "android.intent.category.OPENABLE";
field public static final java.lang.String CATEGORY_PREFERENCE = "android.intent.category.PREFERENCE";
field public static final java.lang.String CATEGORY_SAMPLE_CODE = "android.intent.category.SAMPLE_CODE";
@@ -7543,12 +7576,12 @@
field public static final int FLAG_ACTIVITY_BROUGHT_TO_FRONT = 4194304; // 0x400000
field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
field public static final int FLAG_ACTIVITY_CLEAR_TOP = 67108864; // 0x4000000
- field public static final int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 524288; // 0x80000
+ field public static final deprecated int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 524288; // 0x80000
field public static final int FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS = 8388608; // 0x800000
field public static final int FLAG_ACTIVITY_FORWARD_RESULT = 33554432; // 0x2000000
field public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 1048576; // 0x100000
field public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 134217728; // 0x8000000
- field public static final int FLAG_ACTIVITY_NEW_DOCUMENT = 268959744; // 0x10080000
+ field public static final int FLAG_ACTIVITY_NEW_DOCUMENT = 524288; // 0x80000
field public static final int FLAG_ACTIVITY_NEW_TASK = 268435456; // 0x10000000
field public static final int FLAG_ACTIVITY_NO_ANIMATION = 65536; // 0x10000
field public static final int FLAG_ACTIVITY_NO_HISTORY = 1073741824; // 0x40000000
@@ -7916,7 +7949,6 @@
public class SyncRequest implements android.os.Parcelable {
method public int describeContents();
- method public boolean isExpedited();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
}
@@ -7931,7 +7963,6 @@
method public android.content.SyncRequest.Builder setIgnoreSettings(boolean);
method public android.content.SyncRequest.Builder setManual(boolean);
method public android.content.SyncRequest.Builder setNoRetry(boolean);
- method public android.content.SyncRequest.Builder setPriority(int);
method public android.content.SyncRequest.Builder setSyncAdapter(android.accounts.Account, java.lang.String);
method public android.content.SyncRequest.Builder syncOnce();
method public android.content.SyncRequest.Builder syncPeriodic(long, long);
@@ -8028,6 +8059,7 @@
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int DOCUMENT_LAUNCH_ALWAYS = 2; // 0x2
field public static final int DOCUMENT_LAUNCH_INTO_EXISTING = 1; // 0x1
+ field public static final int DOCUMENT_LAUNCH_NEVER = 3; // 0x3
field public static final int DOCUMENT_LAUNCH_NONE = 0; // 0x0
field public static final int FLAG_ALLOW_TASK_REPARENTING = 64; // 0x40
field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
@@ -8068,6 +8100,7 @@
field public int documentLaunchMode;
field public int flags;
field public int launchMode;
+ field public int maxRecents;
field public java.lang.String parentActivityName;
field public java.lang.String permission;
field public int screenOrientation;
@@ -8234,11 +8267,11 @@
}
public static abstract interface LauncherApps.OnAppsChangedListener {
- method public abstract void onPackageAdded(java.lang.String, android.os.UserHandle);
- method public abstract void onPackageChanged(java.lang.String, android.os.UserHandle);
- method public abstract void onPackageRemoved(java.lang.String, android.os.UserHandle);
- method public abstract void onPackagesAvailable(java.lang.String[], android.os.UserHandle, boolean);
- method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
+ method public abstract void onPackageAdded(android.os.UserHandle, java.lang.String);
+ method public abstract void onPackageChanged(android.os.UserHandle, java.lang.String);
+ method public abstract void onPackageRemoved(android.os.UserHandle, java.lang.String);
+ method public abstract void onPackagesAvailable(android.os.UserHandle, java.lang.String[], boolean);
+ method public abstract void onPackagesUnavailable(android.os.UserHandle, java.lang.String[], boolean);
}
public class PackageInfo implements android.os.Parcelable {
@@ -10194,6 +10227,7 @@
method public void concat(android.graphics.Matrix);
method public void drawARGB(int, int, int, int);
method public void drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint);
+ method public void drawArc(float, float, float, float, float, float, boolean, android.graphics.Paint);
method public void drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint);
method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint);
method public void drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint);
@@ -10208,6 +10242,7 @@
method public void drawLines(float[], int, int, android.graphics.Paint);
method public void drawLines(float[], android.graphics.Paint);
method public void drawOval(android.graphics.RectF, android.graphics.Paint);
+ method public void drawOval(float, float, float, float, android.graphics.Paint);
method public void drawPaint(android.graphics.Paint);
method public void drawPath(android.graphics.Path, android.graphics.Paint);
method public void drawPicture(android.graphics.Picture);
@@ -10717,6 +10752,7 @@
ctor public Path();
ctor public Path(android.graphics.Path);
method public void addArc(android.graphics.RectF, float, float);
+ method public void addArc(float, float, float, float, float, float);
method public void addCircle(float, float, float, android.graphics.Path.Direction);
method public void addOval(android.graphics.RectF, android.graphics.Path.Direction);
method public void addOval(float, float, float, float, android.graphics.Path.Direction);
@@ -10726,9 +10762,12 @@
method public void addRect(android.graphics.RectF, android.graphics.Path.Direction);
method public void addRect(float, float, float, float, android.graphics.Path.Direction);
method public void addRoundRect(android.graphics.RectF, float, float, android.graphics.Path.Direction);
+ method public void addRoundRect(float, float, float, float, float, float, android.graphics.Path.Direction);
method public void addRoundRect(android.graphics.RectF, float[], android.graphics.Path.Direction);
+ method public void addRoundRect(float, float, float, float, float[], android.graphics.Path.Direction);
method public void arcTo(android.graphics.RectF, float, float, boolean);
method public void arcTo(android.graphics.RectF, float, float);
+ method public void arcTo(float, float, float, float, float, float, boolean);
method public void close();
method public void computeBounds(android.graphics.RectF, boolean);
method public void cubicTo(float, float, float, float, float, float);
@@ -11488,6 +11527,7 @@
public class RippleDrawable extends android.graphics.drawable.LayerDrawable {
ctor public RippleDrawable(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
+ method public void setColor(android.content.res.ColorStateList);
}
public class RotateDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
@@ -11951,14 +11991,18 @@
method public int getMinDelay();
method public java.lang.String getName();
method public float getPower();
+ method public int getReportingMode();
method public float getResolution();
method public java.lang.String getStringType();
method public int getType();
method public java.lang.String getVendor();
method public int getVersion();
method public boolean isWakeUpSensor();
+ field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
+ field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
+ field public static final int REPORTING_MODE_ON_CHANGE = 1; // 0x1
+ field public static final int REPORTING_MODE_SPECIAL_TRIGGER = 3; // 0x3
field public static final java.lang.String SENSOR_STRING_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR = "android.sensor.non_wake_up_proximity_sensor";
- field public static final java.lang.String SENSOR_STRING_TYPE_WAKE_UP_TILT_DETECTOR = "android.sensor.wake_up_tilt_detector";
field public static final java.lang.String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
field public static final java.lang.String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature";
field public static final java.lang.String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector";
@@ -12039,7 +12083,6 @@
field public static final int TYPE_WAKE_UP_ROTATION_VECTOR = 31; // 0x1f
field public static final int TYPE_WAKE_UP_STEP_COUNTER = 38; // 0x26
field public static final int TYPE_WAKE_UP_STEP_DETECTOR = 37; // 0x25
- field public static final int TYPE_WAKE_UP_TILT_DETECTOR = 41; // 0x29
}
public class SensorEvent {
@@ -12260,6 +12303,7 @@
field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_PHYSICAL_SIZE;
field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_PIXEL_ARRAY_SIZE;
field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_SENSITIVITY_RANGE;
+ field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_TIMESTAMP_CALIBRATION;
field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_WHITE_LEVEL;
field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_MAX_ANALOG_SENSITIVITY;
field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_ORIENTATION;
@@ -12468,6 +12512,8 @@
field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG = 1; // 0x1
field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB = 4; // 0x4
field public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB = 0; // 0x0
+ field public static final int SENSOR_INFO_TIMESTAMP_CALIBRATION_CALIBRATED = 1; // 0x1
+ field public static final int SENSOR_INFO_TIMESTAMP_CALIBRATION_UNCALIBRATED = 0; // 0x0
field public static final int SENSOR_REFERENCE_ILLUMINANT1_CLOUDY_WEATHER = 10; // 0xa
field public static final int SENSOR_REFERENCE_ILLUMINANT1_COOL_WHITE_FLUORESCENT = 14; // 0xe
field public static final int SENSOR_REFERENCE_ILLUMINANT1_D50 = 23; // 0x17
@@ -12646,6 +12692,7 @@
field public static final android.hardware.camera2.CaptureResult.Key SENSOR_FRAME_DURATION;
field public static final android.hardware.camera2.CaptureResult.Key SENSOR_GREEN_SPLIT;
field public static final android.hardware.camera2.CaptureResult.Key SENSOR_NEUTRAL_COLOR_POINT;
+ field public static final android.hardware.camera2.CaptureResult.Key SENSOR_ROLLING_SHUTTER_SKEW;
field public static final android.hardware.camera2.CaptureResult.Key SENSOR_SENSITIVITY;
field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TEST_PATTERN_DATA;
field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TEST_PATTERN_MODE;
@@ -12804,199 +12851,6 @@
}
-package android.hardware.hdmi {
-
- public final class HdmiCec {
- method public static java.lang.String getDefaultDeviceName(int);
- method public static int getTypeFromAddress(int);
- method public static boolean isValidAddress(int);
- method public static boolean isValidType(int);
- field public static final int ADDR_AUDIO_SYSTEM = 5; // 0x5
- field public static final int ADDR_BROADCAST = 15; // 0xf
- field public static final int ADDR_INVALID = -1; // 0xffffffff
- field public static final int ADDR_PLAYBACK_1 = 4; // 0x4
- field public static final int ADDR_PLAYBACK_2 = 8; // 0x8
- field public static final int ADDR_PLAYBACK_3 = 11; // 0xb
- field public static final int ADDR_RECORDER_1 = 1; // 0x1
- field public static final int ADDR_RECORDER_2 = 2; // 0x2
- field public static final int ADDR_RECORDER_3 = 9; // 0x9
- field public static final int ADDR_RESERVED_1 = 12; // 0xc
- field public static final int ADDR_RESERVED_2 = 13; // 0xd
- field public static final int ADDR_SPECIFIC_USE = 14; // 0xe
- field public static final int ADDR_TUNER_1 = 3; // 0x3
- field public static final int ADDR_TUNER_2 = 6; // 0x6
- field public static final int ADDR_TUNER_3 = 7; // 0x7
- field public static final int ADDR_TUNER_4 = 10; // 0xa
- field public static final int ADDR_TV = 0; // 0x0
- field public static final int ADDR_UNREGISTERED = 15; // 0xf
- field public static final int DEVICE_AUDIO_SYSTEM = 5; // 0x5
- field public static final int DEVICE_INACTIVE = -1; // 0xffffffff
- field public static final int DEVICE_PLAYBACK = 4; // 0x4
- field public static final int DEVICE_RECORDER = 1; // 0x1
- field public static final int DEVICE_RESERVED = 2; // 0x2
- field public static final int DEVICE_TUNER = 3; // 0x3
- field public static final int DEVICE_TV = 0; // 0x0
- field public static final int MESSAGE_ABORT = 255; // 0xff
- field public static final int MESSAGE_ACTIVE_SOURCE = 130; // 0x82
- field public static final int MESSAGE_CEC_VERSION = 158; // 0x9e
- field public static final int MESSAGE_CLEAR_ANALOG_TIMER = 51; // 0x33
- field public static final int MESSAGE_CLEAR_DIGITAL_TIMER = 153; // 0x99
- field public static final int MESSAGE_CLEAR_EXTERNAL_TIMER = 161; // 0xa1
- field public static final int MESSAGE_DECK_CONTROL = 66; // 0x42
- field public static final int MESSAGE_DECK_STATUS = 27; // 0x1b
- field public static final int MESSAGE_DEVICE_VENDOR_ID = 135; // 0x87
- field public static final int MESSAGE_FEATURE_ABORT = 0; // 0x0
- field public static final int MESSAGE_GET_CEC_VERSION = 159; // 0x9f
- field public static final int MESSAGE_GET_MENU_LANGUAGE = 145; // 0x91
- field public static final int MESSAGE_GIVE_AUDIO_STATUS = 113; // 0x71
- field public static final int MESSAGE_GIVE_DECK_STATUS = 26; // 0x1a
- field public static final int MESSAGE_GIVE_DEVICE_POWER_STATUS = 143; // 0x8f
- field public static final int MESSAGE_GIVE_DEVICE_VENDOR_ID = 140; // 0x8c
- field public static final int MESSAGE_GIVE_OSD_NAME = 70; // 0x46
- field public static final int MESSAGE_GIVE_PHYSICAL_ADDRESS = 131; // 0x83
- field public static final int MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS = 125; // 0x7d
- field public static final int MESSAGE_GIVE_TUNER_DEVICE_STATUS = 8; // 0x8
- field public static final int MESSAGE_IMAGE_VIEW_ON = 4; // 0x4
- field public static final int MESSAGE_INACTIVE_SOURCE = 157; // 0x9d
- field public static final int MESSAGE_INITIATE_ARC = 192; // 0xc0
- field public static final int MESSAGE_MENU_REQUEST = 141; // 0x8d
- field public static final int MESSAGE_MENU_STATUS = 142; // 0x8e
- field public static final int MESSAGE_PLAY = 65; // 0x41
- field public static final int MESSAGE_RECORD_OFF = 11; // 0xb
- field public static final int MESSAGE_RECORD_ON = 9; // 0x9
- field public static final int MESSAGE_RECORD_STATUS = 10; // 0xa
- field public static final int MESSAGE_RECORD_TV_SCREEN = 15; // 0xf
- field public static final int MESSAGE_REPORT_ARC_INITIATED = 193; // 0xc1
- field public static final int MESSAGE_REPORT_ARC_TERMINATED = 194; // 0xc2
- field public static final int MESSAGE_REPORT_AUDIO_STATUS = 122; // 0x7a
- field public static final int MESSAGE_REPORT_PHYSICAL_ADDRESS = 132; // 0x84
- field public static final int MESSAGE_REPORT_POWER_STATUS = 144; // 0x90
- field public static final int MESSAGE_REQUEST_ACTIVE_SOURCE = 133; // 0x85
- field public static final int MESSAGE_REQUEST_ARC_INITIATION = 195; // 0xc3
- field public static final int MESSAGE_REQUEST_ARC_TERMINATION = 196; // 0xc4
- field public static final int MESSAGE_ROUTING_CHANGE = 128; // 0x80
- field public static final int MESSAGE_ROUTING_INFORMATION = 129; // 0x81
- field public static final int MESSAGE_SELECT_ANALOG_SERVICE = 146; // 0x92
- field public static final int MESSAGE_SELECT_DIGITAL_SERVICE = 147; // 0x93
- field public static final int MESSAGE_SET_ANALOG_TIMER = 52; // 0x34
- field public static final int MESSAGE_SET_AUDIO_RATE = 154; // 0x9a
- field public static final int MESSAGE_SET_DIGITAL_TIMER = 151; // 0x97
- field public static final int MESSAGE_SET_EXTERNAL_TIMER = 162; // 0xa2
- field public static final int MESSAGE_SET_MENU_LANGUAGE = 50; // 0x32
- field public static final int MESSAGE_SET_OSD_NAME = 71; // 0x47
- field public static final int MESSAGE_SET_OSD_STRING = 100; // 0x64
- field public static final int MESSAGE_SET_STREAM_PATH = 134; // 0x86
- field public static final int MESSAGE_SET_SYSTEM_AUDIO_MODE = 114; // 0x72
- field public static final int MESSAGE_SET_TIMER_PROGRAM_TITLE = 103; // 0x67
- field public static final int MESSAGE_STANDBY = 54; // 0x36
- field public static final int MESSAGE_SYSTEM_AUDIO_MODE_REQUEST = 112; // 0x70
- field public static final int MESSAGE_SYSTEM_AUDIO_MODE_STATUS = 126; // 0x7e
- field public static final int MESSAGE_TERMINATE_ARC = 197; // 0xc5
- field public static final int MESSAGE_TEXT_VIEW_ON = 13; // 0xd
- field public static final int MESSAGE_TIMER_CLEARED_STATUS = 67; // 0x43
- field public static final int MESSAGE_TIMER_STATUS = 53; // 0x35
- field public static final int MESSAGE_TUNER_DEVICE_STATUS = 7; // 0x7
- field public static final int MESSAGE_TUNER_STEP_DECREMENT = 6; // 0x6
- field public static final int MESSAGE_TUNER_STEP_INCREMENT = 5; // 0x5
- field public static final int MESSAGE_USER_CONTROL_PRESSED = 68; // 0x44
- field public static final int MESSAGE_USER_CONTROL_RELEASED = 69; // 0x45
- field public static final int MESSAGE_VENDOR_COMMAND = 137; // 0x89
- field public static final int MESSAGE_VENDOR_COMMAND_WITH_ID = 160; // 0xa0
- field public static final int MESSAGE_VENDOR_REMOTE_BUTTON_DOWN = 138; // 0x8a
- field public static final int MESSAGE_VENDOR_REMOTE_BUTTON_UP = 139; // 0x8b
- field public static final int POWER_STATUS_ON = 0; // 0x0
- field public static final int POWER_STATUS_STANDBY = 1; // 0x1
- field public static final int POWER_STATUS_TRANSIENT_TO_ON = 2; // 0x2
- field public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3; // 0x3
- field public static final int POWER_STATUS_UNKNOWN = -1; // 0xffffffff
- field public static final int RESULT_ALREADY_IN_PROGRESS = 4; // 0x4
- field public static final int RESULT_EXCEPTION = 5; // 0x5
- field public static final int RESULT_SOURCE_NOT_AVAILABLE = 2; // 0x2
- field public static final int RESULT_SUCCESS = 0; // 0x0
- field public static final int RESULT_TARGET_NOT_AVAILABLE = 3; // 0x3
- field public static final int RESULT_TIMEOUT = 1; // 0x1
- field public static final int UNKNOWN_VENDOR_ID = 16777215; // 0xffffff
- }
-
- public final class HdmiCecClient {
- method public boolean isTvOn();
- method public void sendActiveSource();
- method public void sendGiveDevicePowerStatus(int);
- method public void sendImageViewOn();
- method public void sendInactiveSource();
- method public void sendTextViewOn();
- }
-
- public static abstract class HdmiCecClient.Listener {
- ctor public HdmiCecClient.Listener();
- method public void onCableStatusChanged(boolean);
- method public void onMessageReceived(android.hardware.hdmi.HdmiCecMessage);
- }
-
- public final class HdmiCecDeviceInfo implements android.os.Parcelable {
- method public int describeContents();
- method public int getDeviceType();
- method public java.lang.String getDisplayName();
- method public int getLogicalAddress();
- method public int getPhysicalAddress();
- method public int getVendorId();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- }
-
- public final class HdmiCecManager {
- method public android.hardware.hdmi.HdmiCecClient getClient(int, android.hardware.hdmi.HdmiCecClient.Listener);
- }
-
- public final class HdmiCecMessage implements android.os.Parcelable {
- ctor public HdmiCecMessage(int, int, int, byte[]);
- method public int describeContents();
- method public int getDestination();
- method public int getOpcode();
- method public byte[] getParams();
- method public int getSource();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- field public static final byte[] EMPTY_PARAM;
- }
-
- public final class HdmiControlManager {
- method public void addHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
- method public android.hardware.hdmi.HdmiPlaybackClient getPlaybackClient();
- method public android.hardware.hdmi.HdmiTvClient getTvClient();
- method public void removeHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
- }
-
- public static abstract interface HdmiControlManager.HotplugEventListener {
- method public abstract void onReceived(android.hardware.hdmi.HdmiHotplugEvent);
- }
-
- public final class HdmiHotplugEvent implements android.os.Parcelable {
- method public int describeContents();
- method public int getPort();
- method public boolean isConnected();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- }
-
- public final class HdmiPlaybackClient {
- method public void oneTouchPlay(android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback);
- method public void queryDisplayStatus(android.hardware.hdmi.HdmiPlaybackClient.DisplayStatusCallback);
- }
-
- public static abstract interface HdmiPlaybackClient.DisplayStatusCallback {
- method public abstract void onComplete(int);
- }
-
- public static abstract interface HdmiPlaybackClient.OneTouchPlayCallback {
- method public abstract void onComplete(int);
- }
-
- public final class HdmiTvClient {
- }
-
-}
-
package android.hardware.input {
public final class InputManager {
@@ -13868,6 +13722,7 @@
method public void adjustStreamVolume(int, int, int);
method public void adjustSuggestedStreamVolume(int, int, int);
method public void adjustVolume(int, int);
+ method public int allocateAudioSessionId();
method public void dispatchMediaKeyEvent(android.view.KeyEvent);
method public int getMode();
method public java.lang.String getParameters(java.lang.String);
@@ -13928,6 +13783,7 @@
field public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = -3; // 0xfffffffd
field public static final int AUDIOFOCUS_REQUEST_FAILED = 0; // 0x0
field public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; // 0x1
+ field public static final int ERROR = -1; // 0xffffffff
field public static final java.lang.String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
field public static final java.lang.String EXTRA_SCO_AUDIO_PREVIOUS_STATE = "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
field public static final java.lang.String EXTRA_SCO_AUDIO_STATE = "android.media.extra.SCO_AUDIO_STATE";
@@ -14107,6 +13963,7 @@
method public static boolean hasProfile(int);
method public static boolean hasProfile(int, int);
field public static final int QUALITY_1080P = 6; // 0x6
+ field public static final int QUALITY_2160P = 8; // 0x8
field public static final int QUALITY_480P = 4; // 0x4
field public static final int QUALITY_720P = 5; // 0x5
field public static final int QUALITY_CIF = 3; // 0x3
@@ -14115,6 +13972,7 @@
field public static final int QUALITY_QCIF = 2; // 0x2
field public static final int QUALITY_QVGA = 7; // 0x7
field public static final int QUALITY_TIME_LAPSE_1080P = 1006; // 0x3ee
+ field public static final int QUALITY_TIME_LAPSE_2160P = 1008; // 0x3f0
field public static final int QUALITY_TIME_LAPSE_480P = 1004; // 0x3ec
field public static final int QUALITY_TIME_LAPSE_720P = 1005; // 0x3ed
field public static final int QUALITY_TIME_LAPSE_CIF = 1003; // 0x3eb
@@ -15958,7 +15816,9 @@
method public static final android.net.Uri buildChannelsUriForInput(android.content.ComponentName);
method public static final android.net.Uri buildChannelsUriForInput(android.content.ComponentName, boolean);
method public static final android.net.Uri buildProgramUri(long);
+ method public static final android.net.Uri buildProgramsUriForChannel(long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri);
+ method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
field public static final java.lang.String AUTHORITY = "android.media.tv";
}
@@ -15989,7 +15849,7 @@
field public static final int SERVICE_TYPE_OTHER = 0; // 0x0
field public static final int TYPE_1SEG = 263168; // 0x40400
field public static final int TYPE_ATSC_C = 197120; // 0x30200
- field public static final int TYPE_ATSC_M_H = 197120; // 0x30200
+ field public static final int TYPE_ATSC_M_H = 197376; // 0x30300
field public static final int TYPE_ATSC_T = 196608; // 0x30000
field public static final int TYPE_CMMB = 327936; // 0x50100
field public static final int TYPE_DTMB = 327680; // 0x50000
@@ -16005,8 +15865,11 @@
field public static final int TYPE_ISDB_S = 262656; // 0x40200
field public static final int TYPE_ISDB_T = 262144; // 0x40000
field public static final int TYPE_ISDB_TB = 262400; // 0x40100
+ field public static final int TYPE_NTSC = 1; // 0x1
field public static final int TYPE_OTHER = 0; // 0x0
+ field public static final int TYPE_PAL = 2; // 0x2
field public static final int TYPE_PASSTHROUGH = 65536; // 0x10000
+ field public static final int TYPE_SECAM = 3; // 0x3
field public static final int TYPE_S_DMB = 393472; // 0x60100
field public static final int TYPE_T_DMB = 393216; // 0x60000
}
@@ -16056,9 +15919,15 @@
method public android.content.Intent getIntentForSettingsActivity();
method public android.content.Intent getIntentForSetupActivity();
method public android.content.pm.ServiceInfo getServiceInfo();
+ method public int getType();
+ method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
method public void writeToParcel(android.os.Parcel, int);
field public static final java.lang.String EXTRA_SERVICE_NAME = "serviceName";
+ field public static final int TYPE_HDMI = 1; // 0x1
+ field public static final int TYPE_PASSTHROUGH = 3; // 0x3
+ field public static final int TYPE_TUNER = 2; // 0x2
+ field public static final int TYPE_VIRTUAL = 0; // 0x0
}
public final class TvInputManager {
@@ -16096,11 +15965,12 @@
method public void setOverlayViewEnabled(boolean);
}
- public class TvView extends android.view.SurfaceView {
+ public class TvView extends android.view.ViewGroup {
ctor public TvView(android.content.Context);
ctor public TvView(android.content.Context, android.util.AttributeSet);
ctor public TvView(android.content.Context, android.util.AttributeSet, int);
method public boolean dispatchUnhandledInputEvent(android.view.InputEvent);
+ method protected void onLayout(boolean, int, int, int, int);
method public boolean onUnhandledInputEvent(android.view.InputEvent);
method public void reset();
method public void setOnUnhandledInputEventListener(android.media.tv.TvView.OnUnhandledInputEventListener);
@@ -16259,28 +16129,27 @@
method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network);
method public android.net.NetworkInfo getNetworkInfo(int);
method public deprecated int getNetworkPreference();
+ method public static android.net.Network getProcessDefaultNetwork();
method public boolean isActiveNetworkMetered();
- method public boolean isNetworkActive();
+ method public boolean isDefaultNetworkActive();
method public static boolean isNetworkTypeValid(int);
- method public android.net.NetworkRequest listenForNetwork(android.net.NetworkCapabilities, android.net.ConnectivityManager.NetworkCallbackListener);
- method public void registerNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
- method public void releaseNetworkRequest(android.net.NetworkRequest);
+ method public void registerDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
+ method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
method public void reportBadNetwork(android.net.Network);
- method public android.net.NetworkRequest requestNetwork(android.net.NetworkCapabilities, android.net.ConnectivityManager.NetworkCallbackListener);
- method public android.net.NetworkRequest requestNetwork(android.net.NetworkCapabilities, android.app.PendingIntent);
+ method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
method public deprecated boolean requestRouteToHost(int, int);
method public deprecated void setNetworkPreference(int);
+ method public static boolean setProcessDefaultNetwork(android.net.Network);
method public deprecated int startUsingNetworkFeature(int, java.lang.String);
method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
- method public void unregisterNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
+ method public void unregisterDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
+ method public void unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover";
field public static final deprecated java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
- field public static final java.lang.String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork";
- field public static final java.lang.String EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES = "networkRequestNetworkCapabilities";
field public static final java.lang.String EXTRA_NETWORK_TYPE = "networkType";
field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
@@ -16297,14 +16166,13 @@
field public static final int TYPE_WIMAX = 6; // 0x6
}
- public static class ConnectivityManager.NetworkCallbackListener {
- ctor public ConnectivityManager.NetworkCallbackListener();
- method public void onAvailable(android.net.NetworkRequest, android.net.Network);
- method public void onLinkPropertiesChanged(android.net.NetworkRequest, android.net.Network, android.net.LinkProperties);
- method public void onLosing(android.net.NetworkRequest, android.net.Network, int);
- method public void onLost(android.net.NetworkRequest, android.net.Network);
- method public void onNetworkCapabilitiesChanged(android.net.NetworkRequest, android.net.Network, android.net.NetworkCapabilities);
- method public void onReleased(android.net.NetworkRequest);
+ public static class ConnectivityManager.NetworkCallback {
+ ctor public ConnectivityManager.NetworkCallback();
+ method public void onAvailable(android.net.Network);
+ method public void onCapabilitiesChanged(android.net.Network, android.net.NetworkCapabilities);
+ method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
+ method public void onLosing(android.net.Network, int);
+ method public void onLost(android.net.Network);
}
public static abstract interface ConnectivityManager.OnNetworkActiveListener {
@@ -16331,46 +16199,34 @@
field public int serverAddress;
}
- public class LinkAddress implements android.os.Parcelable {
+ public final class IpPrefix implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
- method public int getFlags();
- method public int getNetworkPrefixLength();
- method public int getScope();
- method public boolean isSameAddressAs(android.net.LinkAddress);
- method public void writeToParcel(android.os.Parcel, int);
- }
-
- public class LinkProperties implements android.os.Parcelable {
- ctor public LinkProperties();
- ctor public LinkProperties(android.net.LinkProperties);
- method public void addDns(java.net.InetAddress);
- method public boolean addLinkAddress(android.net.LinkAddress);
- method public void addRoute(android.net.RouteInfo);
- method public void clear();
- method public int describeContents();
- method public java.util.Collection<java.lang.String> getAllInterfaceNames();
- method public java.util.Collection<java.net.InetAddress> getDnses();
- method public java.lang.String getDomains();
- method public android.net.ProxyInfo getHttpProxy();
- method public java.lang.String getInterfaceName();
- method public java.util.Collection<android.net.LinkAddress> getLinkAddresses();
- method public java.util.Collection<android.net.RouteInfo> getRoutes();
- method public boolean hasIPv4Address();
- method public boolean hasIPv6Address();
- method public boolean removeLinkAddress(android.net.LinkAddress);
- method public void setDomains(java.lang.String);
- method public void setHttpProxy(android.net.ProxyInfo);
- method public void setInterfaceName(java.lang.String);
- method public void setLinkAddresses(java.util.Collection<android.net.LinkAddress>);
+ method public int getPrefixLength();
+ method public byte[] getRawAddress();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
}
- public static class LinkProperties.CompareResult {
- ctor public LinkProperties.CompareResult();
- field public java.util.Collection added;
- field public java.util.Collection removed;
+ public class LinkAddress implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.net.InetAddress getAddress();
+ method public int getFlags();
+ method public int getPrefixLength();
+ method public int getScope();
+ method public void writeToParcel(android.os.Parcel, int);
+ }
+
+ public final class LinkProperties implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.util.List<java.net.InetAddress> getDnsServers();
+ method public java.lang.String getDomains();
+ method public android.net.ProxyInfo getHttpProxy();
+ method public java.lang.String getInterfaceName();
+ method public java.util.List<android.net.LinkAddress> getLinkAddresses();
+ method public java.util.List<android.net.RouteInfo> getRoutes();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
}
public class LocalServerSocket {
@@ -16442,33 +16298,21 @@
}
public class Network implements android.os.Parcelable {
- method public void bindProcess();
method public int describeContents();
method public java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException;
method public java.net.InetAddress getByName(java.lang.String) throws java.net.UnknownHostException;
- method public static android.net.Network getProcessBoundNetwork();
- method public javax.net.SocketFactory socketFactory();
- method public static void unbindProcess();
+ method public javax.net.SocketFactory getSocketFactory();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
}
public final class NetworkCapabilities implements android.os.Parcelable {
- ctor public NetworkCapabilities();
ctor public NetworkCapabilities(android.net.NetworkCapabilities);
- method public void addNetworkCapability(int);
- method public void addTransportType(int);
method public int describeContents();
method public int getLinkDownstreamBandwidthKbps();
method public int getLinkUpstreamBandwidthKbps();
- method public java.util.Collection<java.lang.Integer> getNetworkCapabilities();
- method public java.util.Collection<java.lang.Integer> getTransportTypes();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
- method public void removeNetworkCapability(int);
- method public void removeTransportType(int);
- method public void setLinkDownstreamBandwidthKbps(int);
- method public void setLinkUpstreamBandwidthKbps(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int NET_CAPABILITY_CBS = 5; // 0x5
@@ -16542,7 +16386,27 @@
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
- field public final android.net.NetworkCapabilities networkCapabilities;
+ }
+
+ public static class NetworkRequest.Builder {
+ ctor public NetworkRequest.Builder();
+ method public android.net.NetworkRequest.Builder addCapability(int);
+ method public android.net.NetworkRequest.Builder addTransportType(int);
+ method public android.net.NetworkRequest build();
+ method public android.net.NetworkRequest.Builder removeCapability(int);
+ method public android.net.NetworkRequest.Builder removeTransportType(int);
+ }
+
+ public abstract interface PSKKeyManager {
+ method public abstract java.lang.String chooseClientKeyIdentity(java.lang.String, java.net.Socket);
+ method public abstract java.lang.String chooseClientKeyIdentity(java.lang.String, javax.net.ssl.SSLEngine);
+ method public abstract java.lang.String chooseServerKeyIdentityHint(java.net.Socket);
+ method public abstract java.lang.String chooseServerKeyIdentityHint(javax.net.ssl.SSLEngine);
+ method public abstract javax.crypto.SecretKey getKey(java.lang.String, java.lang.String, java.net.Socket);
+ method public abstract javax.crypto.SecretKey getKey(java.lang.String, java.lang.String, javax.net.ssl.SSLEngine);
+ field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
+ field public static final int MAX_IDENTITY_LENGTH_BYTES = 128; // 0x80
+ field public static final int MAX_KEY_LENGTH_BYTES = 256; // 0x100
}
public class ParseException extends java.lang.RuntimeException {
@@ -16571,18 +16435,15 @@
method public void writeToParcel(android.os.Parcel, int);
}
- public class RouteInfo implements android.os.Parcelable {
- ctor public RouteInfo(android.net.LinkAddress, java.net.InetAddress, java.lang.String);
- ctor public RouteInfo(android.net.LinkAddress, java.net.InetAddress);
- ctor public RouteInfo(java.net.InetAddress);
- ctor public RouteInfo(android.net.LinkAddress);
+ public final class RouteInfo implements android.os.Parcelable {
method public int describeContents();
- method public android.net.LinkAddress getDestination();
+ method public android.net.IpPrefix getDestination();
method public java.net.InetAddress getGateway();
method public java.lang.String getInterface();
method public boolean isDefaultRoute();
method public boolean matches(java.net.InetAddress);
method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
}
public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
@@ -20672,7 +20533,8 @@
public class BatteryManager {
ctor public BatteryManager();
- method public android.os.BatteryProperty getProperty(int) throws android.os.RemoteException;
+ method public int getIntProperty(int);
+ method public long getLongProperty(int);
field public static final int BATTERY_HEALTH_COLD = 7; // 0x7
field public static final int BATTERY_HEALTH_DEAD = 4; // 0x4
field public static final int BATTERY_HEALTH_GOOD = 2; // 0x2
@@ -20683,6 +20545,11 @@
field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
+ field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
+ field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
+ field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
+ field public static final int BATTERY_PROPERTY_CURRENT_NOW = 2; // 0x2
+ field public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5; // 0x5
field public static final int BATTERY_STATUS_CHARGING = 2; // 0x2
field public static final int BATTERY_STATUS_DISCHARGING = 3; // 0x3
field public static final int BATTERY_STATUS_FULL = 5; // 0x5
@@ -20700,20 +20567,6 @@
field public static final java.lang.String EXTRA_VOLTAGE = "voltage";
}
- public class BatteryProperty implements android.os.Parcelable {
- method public int describeContents();
- method public int getInt();
- method public long getLong();
- method public void readFromParcel(android.os.Parcel);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int CAPACITY = 4; // 0x4
- field public static final int CHARGE_COUNTER = 1; // 0x1
- field public static final android.os.Parcelable.Creator CREATOR;
- field public static final int CURRENT_AVERAGE = 3; // 0x3
- field public static final int CURRENT_NOW = 2; // 0x2
- field public static final int ENERGY_COUNTER = 5; // 0x5
- }
-
public class Binder implements android.os.IBinder {
ctor public Binder();
method public void attachInterface(android.os.IInterface, java.lang.String);
@@ -21695,6 +21548,7 @@
method public java.util.List<android.os.UserHandle> getUserProfiles();
method public android.os.Bundle getUserRestrictions();
method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
+ method public boolean hasUserRestriction(java.lang.String);
method public boolean isUserAGoat();
method public boolean isUserRunning(android.os.UserHandle);
method public boolean isUserRunningOrStopping(android.os.UserHandle);
@@ -22500,6 +22354,7 @@
method protected void onDisconnected();
method protected abstract void onPrintJobQueued(android.printservice.PrintJob);
method protected abstract void onRequestCancelPrintJob(android.printservice.PrintJob);
+ field public static final java.lang.String EXTRA_PRINTER_INFO = "android.intent.extra.print.PRINTER_INFO";
field public static final java.lang.String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO";
field public static final java.lang.String SERVICE_INTERFACE = "android.printservice.PrintService";
field public static final java.lang.String SERVICE_META_DATA = "android.printservice";
@@ -23992,21 +23847,21 @@
public final class DocumentsContract {
method public static android.net.Uri buildChildDocumentsUri(java.lang.String, java.lang.String);
- method public static android.net.Uri buildChildDocumentsViaUri(android.net.Uri, java.lang.String);
+ method public static android.net.Uri buildChildDocumentsUriUsingTree(android.net.Uri, java.lang.String);
method public static android.net.Uri buildDocumentUri(java.lang.String, java.lang.String);
- method public static android.net.Uri buildDocumentViaUri(android.net.Uri, java.lang.String);
+ method public static android.net.Uri buildDocumentUriUsingTree(android.net.Uri, java.lang.String);
method public static android.net.Uri buildRecentDocumentsUri(java.lang.String, java.lang.String);
method public static android.net.Uri buildRootUri(java.lang.String, java.lang.String);
method public static android.net.Uri buildRootsUri(java.lang.String);
method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
- method public static android.net.Uri buildViaUri(java.lang.String, java.lang.String);
+ method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
method public static java.lang.String getDocumentId(android.net.Uri);
method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal);
method public static java.lang.String getRootId(android.net.Uri);
method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
- method public static java.lang.String getViaDocumentId(android.net.Uri);
+ method public static java.lang.String getTreeDocumentId(android.net.Uri);
method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String);
field public static final java.lang.String EXTRA_ERROR = "error";
@@ -24045,7 +23900,7 @@
field public static final java.lang.String COLUMN_TITLE = "title";
field public static final int FLAG_LOCAL_ONLY = 2; // 0x2
field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
- field public static final int FLAG_SUPPORTS_DIR_SELECTION = 16; // 0x10
+ field public static final int FLAG_SUPPORTS_IS_CHILD = 16; // 0x10
field public static final int FLAG_SUPPORTS_RECENTS = 4; // 0x4
field public static final int FLAG_SUPPORTS_SEARCH = 8; // 0x8
}
@@ -24266,7 +24121,6 @@
}
public static final class MediaStore.Audio.Radio {
- ctor public MediaStore.Audio.Radio();
field public static final java.lang.String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/radio";
}
@@ -25649,7 +25503,7 @@
method public void contextDump();
method public static android.renderscript.RenderScript create(android.content.Context);
method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType);
- method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType, long);
+ method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType, int);
method public void destroy();
method public void finish();
method public final android.content.Context getApplicationContext();
@@ -25659,9 +25513,9 @@
method public void setErrorHandler(android.renderscript.RenderScript.RSErrorHandler);
method public void setMessageHandler(android.renderscript.RenderScript.RSMessageHandler);
method public void setPriority(android.renderscript.RenderScript.Priority);
- field public static final long CREATE_FLAG_LOW_LATENCY = 2L; // 0x2L
- field public static final long CREATE_FLAG_LOW_POWER = 4L; // 0x4L
- field public static final long CREATE_FLAG_NONE = 0L; // 0x0L
+ field public static final int CREATE_FLAG_LOW_LATENCY = 2; // 0x2
+ field public static final int CREATE_FLAG_LOW_POWER = 4; // 0x4
+ field public static final int CREATE_FLAG_NONE = 0; // 0x0
}
public static final class RenderScript.ContextType extends java.lang.Enum {
@@ -26178,29 +26032,61 @@
package android.service.fingerprint {
public class FingerprintManager {
- ctor public FingerprintManager(android.content.Context);
+ ctor public FingerprintManager(android.content.Context, android.service.fingerprint.IFingerprintService);
method public void enroll(long);
+ method public void enrollCancel();
method public boolean enrolledAndEnabled();
method public void remove(int);
method public void startListening(android.service.fingerprint.FingerprintManagerReceiver);
method public void stopListening();
+ field public static final int FINGERPRINT_ACQUIRED = 1; // 0x1
+ field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
+ field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 4; // 0x4
+ field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
+ field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
+ field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 16; // 0x10
+ field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 8; // 0x8
field public static final int FINGERPRINT_ERROR = -1; // 0xffffffff
- field public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2; // 0x2
field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
field public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10; // 0xfffffff6
field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
- field public static final int FINGERPRINT_SCANNED = 1; // 0x1
- field public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2; // 0x2
+ field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+ field public static final int FINGERPRINT_PROCESSED = 2; // 0x2
+ field public static final int FINGERPRINT_TEMPLATE_ENROLLING = 3; // 0x3
field public static final int FINGERPRINT_TEMPLATE_REMOVED = 4; // 0x4
}
public class FingerprintManagerReceiver {
ctor public FingerprintManagerReceiver();
+ method public void onAcquired(int);
method public void onEnrollResult(int, int);
method public void onError(int);
+ method public void onProcessed(int);
method public void onRemoved(int);
- method public void onScanned(int, int);
+ }
+
+ public class FingerprintUtils {
+ ctor public FingerprintUtils();
+ method public static void addFingerprintIdForUser(int, android.content.ContentResolver, int);
+ method public static int[] getFingerprintIdsForUser(android.content.ContentResolver, int);
+ method public static boolean removeFingerprintIdForUser(int, android.content.ContentResolver, int);
+ }
+
+ public abstract interface IFingerprintService implements android.os.IInterface {
+ method public abstract void enroll(android.os.IBinder, long, int) throws android.os.RemoteException;
+ method public abstract void enrollCancel(android.os.IBinder, int) throws android.os.RemoteException;
+ method public abstract void remove(android.os.IBinder, int, int) throws android.os.RemoteException;
+ method public abstract void startListening(android.os.IBinder, android.service.fingerprint.IFingerprintServiceReceiver, int) throws android.os.RemoteException;
+ method public abstract void stopListening(android.os.IBinder, int) throws android.os.RemoteException;
+ }
+
+ public abstract interface IFingerprintServiceReceiver implements android.os.IInterface {
+ method public abstract void onAcquired(int) throws android.os.RemoteException;
+ method public abstract void onEnrollResult(int, int) throws android.os.RemoteException;
+ method public abstract void onError(int) throws android.os.RemoteException;
+ method public abstract void onProcessed(int) throws android.os.RemoteException;
+ method public abstract void onRemoved(int) throws android.os.RemoteException;
}
}
@@ -26214,21 +26100,28 @@
method public final void cancelNotification(java.lang.String);
method public final void cancelNotifications(java.lang.String[]);
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
- method public android.service.notification.NotificationListenerService.Ranking getCurrentRanking();
+ method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
method public android.os.IBinder onBind(android.content.Intent);
method public void onListenerConnected();
- method public abstract void onNotificationPosted(android.service.notification.StatusBarNotification);
- method public void onNotificationRankingUpdate();
- method public abstract void onNotificationRemoved(android.service.notification.StatusBarNotification);
+ method public void onNotificationPosted(android.service.notification.StatusBarNotification);
+ method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
+ method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap);
+ method public void onNotificationRemoved(android.service.notification.StatusBarNotification);
+ method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
}
- public static class NotificationListenerService.Ranking implements android.os.Parcelable {
+ public static class NotificationListenerService.Ranking {
+ method public java.lang.String getKey();
+ method public int getRank();
+ method public boolean isAmbient();
+ method public boolean isInterceptedByDoNotDisturb();
+ }
+
+ public static class NotificationListenerService.RankingMap implements android.os.Parcelable {
method public int describeContents();
method public java.lang.String[] getOrderedKeys();
- method public int getRank(java.lang.String);
- method public boolean isAmbient(java.lang.String);
- method public boolean isInterceptedByDoNotDisturb(java.lang.String);
+ method public android.service.notification.NotificationListenerService.Ranking getRanking(java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
}
@@ -26705,6 +26598,7 @@
}
public static final class TextToSpeechClient.EngineStatus {
+ method public java.util.Locale getDefaultLocale();
method public java.lang.String getEnginePackage();
method public java.util.List<android.speech.tts.VoiceInfo> getVoices();
}
@@ -27541,8 +27435,8 @@
field public final int supportedRouteMask;
}
- public class CallCapabilities {
- ctor public CallCapabilities();
+ public final class CallCapabilities {
+ method public static java.lang.String toString(int);
field public static final int ADD_CALL = 16; // 0x10
field public static final int ALL = 511; // 0x1ff
field public static final int CONNECTION_HANDOFF = 256; // 0x100
@@ -27601,8 +27495,10 @@
}
public final class CallServiceAdapter {
+ method public void addConferenceCall(java.lang.String);
method public void handleFailedOutgoingCall(android.telecomm.ConnectionRequest, int, java.lang.String);
method public void handleSuccessfulOutgoingCall(java.lang.String);
+ method public void handoffCall(java.lang.String);
method public void notifyIncomingCall(android.telecomm.CallInfo);
method public void onPostDialWait(java.lang.String, java.lang.String);
method public void setActive(java.lang.String);
@@ -27674,16 +27570,23 @@
public abstract class Connection {
ctor protected Connection();
+ method public final void conference();
method public final android.telecomm.CallAudioState getCallAudioState();
+ method public java.util.List<android.telecomm.Connection> getChildConnections();
method public final android.net.Uri getHandle();
+ method public android.telecomm.Connection getParentConnection();
+ method public boolean isConferenceConnection();
method public boolean isRequestingRingback();
method protected void onAbort();
method protected void onAnswer();
+ method protected void onChildrenChanged(java.util.List<android.telecomm.Connection>);
+ method protected void onConference();
method protected void onDisconnect();
method protected void onHold();
method protected void onPlayDtmfTone(char);
method protected void onPostDialContinue(boolean);
method protected void onReject();
+ method protected void onSeparate();
method protected void onSetAudioState(android.telecomm.CallAudioState);
method protected void onSetSignal(android.os.Bundle);
method protected void onSetState(int);
@@ -27691,10 +27594,13 @@
method protected void onUnhold();
method protected void setActive();
method public void setAudioState(android.telecomm.CallAudioState);
+ method protected void setDestroyed();
method protected void setDialing();
method protected void setDisconnected(int, java.lang.String);
method protected void setHandle(android.net.Uri);
+ method protected void setIsConferenceCapable(boolean);
method protected void setOnHold();
+ method public void setParentConnection(android.telecomm.Connection);
method protected void setRequestingRingback(boolean);
method protected void setRinging();
method public static java.lang.String stateToString(int);
@@ -27702,9 +27608,11 @@
public static abstract interface Connection.Listener {
method public abstract void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
+ method public abstract void onConferenceCapableChanged(android.telecomm.Connection, boolean);
method public abstract void onDestroyed(android.telecomm.Connection);
method public abstract void onDisconnected(android.telecomm.Connection, int, java.lang.String);
method public abstract void onHandleChanged(android.telecomm.Connection, android.net.Uri);
+ method public abstract void onParentConnectionChanged(android.telecomm.Connection, android.telecomm.Connection);
method public abstract void onRequestingRingback(android.telecomm.Connection, boolean);
method public abstract void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
method public abstract void onStateChanged(android.telecomm.Connection, int);
@@ -27713,9 +27621,11 @@
public static class Connection.ListenerBase implements android.telecomm.Connection.Listener {
ctor public Connection.ListenerBase();
method public void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
+ method public void onConferenceCapableChanged(android.telecomm.Connection, boolean);
method public void onDestroyed(android.telecomm.Connection);
method public void onDisconnected(android.telecomm.Connection, int, java.lang.String);
method public void onHandleChanged(android.telecomm.Connection, android.net.Uri);
+ method public void onParentConnectionChanged(android.telecomm.Connection, android.telecomm.Connection);
method public void onRequestingRingback(android.telecomm.Connection, boolean);
method public void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
method public void onStateChanged(android.telecomm.Connection, int);
@@ -27747,9 +27657,13 @@
method public final void answer(java.lang.String);
method public final void call(android.telecomm.CallInfo);
method public final void disconnect(java.lang.String);
+ method public java.util.Collection<android.telecomm.Connection> getAllConnections();
method public final void hold(java.lang.String);
method public final void isCompatibleWith(android.telecomm.CallInfo);
method public final void onAudioStateChanged(java.lang.String, android.telecomm.CallAudioState);
+ method public void onConnectionAdded(android.telecomm.Connection);
+ method public void onConnectionRemoved(android.telecomm.Connection);
+ method public void onCreateConferenceConnection(java.lang.String, android.telecomm.Connection, android.telecomm.Response<java.lang.String, android.telecomm.Connection>);
method public void onCreateConnections(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
method public void onCreateIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
method public void onFindSubscriptions(android.net.Uri, android.telecomm.Response<android.net.Uri, android.telecomm.Subscription>);
@@ -27780,7 +27694,7 @@
method public void mute(boolean);
method public void playDtmfTone(java.lang.String, char);
method public void postDialContinue(java.lang.String, boolean);
- method public void rejectCall(java.lang.String);
+ method public void rejectCall(java.lang.String, boolean, java.lang.String);
method public void setAudioRoute(int);
method public void stopDtmfTone(java.lang.String);
method public void unholdCall(java.lang.String);
@@ -27788,6 +27702,7 @@
public final class InCallCall implements android.os.Parcelable {
method public int describeContents();
+ method public java.util.List<java.lang.String> getCannedSmsResponses();
method public int getCapabilities();
method public long getConnectTimeMillis();
method public android.telecomm.CallServiceDescriptor getCurrentCallServiceDescriptor();
@@ -27832,6 +27747,7 @@
field public static final java.lang.String ACTION_CALL_SERVICE;
field public static final java.lang.String ACTION_CALL_SERVICE_PROVIDER;
field public static final java.lang.String ACTION_CALL_SERVICE_SELECTOR;
+ field public static final java.lang.String ACTION_CHANGE_DEFAULT_PHONE = "android.telecomm.ACTION_CHANGE_DEFAULT_PHONE";
field public static final java.lang.String ACTION_INCOMING_CALL = "android.intent.action.INCOMING_CALL";
field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
@@ -27839,6 +27755,11 @@
field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecomm.extra.CALL_DISCONNECT_MESSAGE";
field public static final java.lang.String EXTRA_CALL_SERVICE_DESCRIPTOR = "android.intent.extra.CALL_SERVICE_DESCRIPTOR";
field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.intent.extra.INCOMING_CALL_EXTRAS";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "package";
+ field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.intent.extra.START_CALL_WITH_SPEAKERPHONE";
+ }
+
+ public class TelecommManager {
}
}
@@ -31069,12 +30990,26 @@
method public static android.util.Range<T> create(T, T);
method public T getLower();
method public T getUpper();
+ method public boolean inRange(T);
}
- public final class Rational {
+ public final class Rational extends java.lang.Number implements java.lang.Comparable {
ctor public Rational(int, int);
+ method public int compareTo(android.util.Rational);
+ method public double doubleValue();
+ method public float floatValue();
method public int getDenominator();
method public int getNumerator();
+ method public int intValue();
+ method public boolean isFinite();
+ method public boolean isInfinite();
+ method public boolean isNaN();
+ method public boolean isZero();
+ method public long longValue();
+ field public static final android.util.Rational NEGATIVE_INFINITY;
+ field public static final android.util.Rational NaN;
+ field public static final android.util.Rational POSITIVE_INFINITY;
+ field public static final android.util.Rational ZERO;
}
public final class Size {
@@ -32625,6 +32560,8 @@
method public android.view.animation.Animation getAnimation();
method public android.os.IBinder getApplicationWindowToken();
method public android.graphics.drawable.Drawable getBackground();
+ method public android.content.res.ColorStateList getBackgroundTint();
+ method public android.graphics.PorterDuff.Mode getBackgroundTintMode();
method public int getBaseline();
method public final int getBottom();
method protected float getBottomFadingEdgeStrength();
@@ -32902,6 +32839,8 @@
method public void setBackgroundColor(int);
method public deprecated void setBackgroundDrawable(android.graphics.drawable.Drawable);
method public void setBackgroundResource(int);
+ method public void setBackgroundTint(android.content.res.ColorStateList);
+ method public void setBackgroundTintMode(android.graphics.PorterDuff.Mode);
method public final void setBottom(int);
method public void setCameraDistance(float);
method public void setClickable(boolean);
@@ -33227,7 +33166,7 @@
method public abstract boolean onTouch(android.view.View, android.view.MotionEvent);
}
- public class ViewAnimationUtils {
+ public final class ViewAnimationUtils {
method public static final android.animation.ValueAnimator createCircularReveal(android.view.View, int, int, float, float);
}
@@ -33692,6 +33631,7 @@
method public android.transition.Transition getSharedElementEnterTransition();
method public android.transition.Transition getSharedElementExitTransition();
method public abstract int getStatusBarColor();
+ method public long getTransitionBackgroundFadeDuration();
method public android.transition.TransitionManager getTransitionManager();
method public abstract int getVolumeControlStream();
method public android.view.WindowManager getWindowManager();
@@ -33750,6 +33690,7 @@
method public abstract void setStatusBarColor(int);
method public abstract void setTitle(java.lang.CharSequence);
method public abstract deprecated void setTitleColor(int);
+ method public void setTransitionBackgroundFadeDuration(long);
method public void setTransitionManager(android.transition.TransitionManager);
method public void setType(int);
method public void setUiOptions(int);
@@ -34764,15 +34705,15 @@
field public static final android.os.Parcelable.Creator CREATOR;
}
- public static final class CursorAnchorInfo.CursorAnchorInfoBuilder {
- ctor public CursorAnchorInfo.CursorAnchorInfoBuilder();
- method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder addCharacterRect(int, float, float, float, float);
+ public static final class CursorAnchorInfo.Builder {
+ ctor public CursorAnchorInfo.Builder();
+ method public android.view.inputmethod.CursorAnchorInfo.Builder addCharacterRect(int, float, float, float, float);
method public android.view.inputmethod.CursorAnchorInfo build();
method public void reset();
- method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setComposingText(int, java.lang.CharSequence);
- method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setInsertionMarkerLocation(float, float, float, float);
- method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setMatrix(android.graphics.Matrix);
- method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setSelectionRange(int, int);
+ method public android.view.inputmethod.CursorAnchorInfo.Builder setComposingText(int, java.lang.CharSequence);
+ method public android.view.inputmethod.CursorAnchorInfo.Builder setInsertionMarkerLocation(float, float, float, float);
+ method public android.view.inputmethod.CursorAnchorInfo.Builder setMatrix(android.graphics.Matrix);
+ method public android.view.inputmethod.CursorAnchorInfo.Builder setSelectionRange(int, int);
}
public class EditorInfo implements android.text.InputType android.os.Parcelable {
@@ -35147,7 +35088,8 @@
package android.webkit {
- public abstract interface ClientCertRequest {
+ public abstract class ClientCertRequest {
+ ctor public ClientCertRequest();
method public abstract void cancel();
method public abstract java.lang.String getHost();
method public abstract java.lang.String[] getKeyTypes();
@@ -35181,12 +35123,15 @@
method public java.lang.String getCookie(java.lang.String);
method public static synchronized android.webkit.CookieManager getInstance();
method public synchronized boolean hasCookies();
- method public void removeAllCookie();
- method public void removeExpiredCookie();
- method public void removeSessionCookie();
+ method public deprecated void removeAllCookie();
+ method public void removeAllCookies(android.webkit.ValueCallback<java.lang.Boolean>);
+ method public deprecated void removeExpiredCookie();
+ method public deprecated void removeSessionCookie();
+ method public void removeSessionCookies(android.webkit.ValueCallback<java.lang.Boolean>);
method public synchronized void setAcceptCookie(boolean);
method public static void setAcceptFileSchemeCookies(boolean);
method public void setCookie(java.lang.String, java.lang.String);
+ method public void setCookie(java.lang.String, java.lang.String, android.webkit.ValueCallback<java.lang.Boolean>);
}
public final class CookieSyncManager extends android.webkit.WebSyncManager {
@@ -35328,12 +35273,25 @@
method public void onRequestFocus(android.webkit.WebView);
method public void onShowCustomView(android.view.View, android.webkit.WebChromeClient.CustomViewCallback);
method public deprecated void onShowCustomView(android.view.View, int, android.webkit.WebChromeClient.CustomViewCallback);
+ method public boolean showFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams);
}
public static abstract interface WebChromeClient.CustomViewCallback {
method public abstract void onCustomViewHidden();
}
+ public static class WebChromeClient.FileChooserParams {
+ ctor public WebChromeClient.FileChooserParams();
+ field public static final int MODE_OPEN_FOLDER = 2; // 0x2
+ field public static final int MODE_OPEN_MULTIPLE = 1; // 0x1
+ field public static final int MODE_SAVE = 4; // 0x4
+ field public java.lang.String acceptTypes;
+ field public boolean capture;
+ field public java.lang.String defaultFilename;
+ field public int mode;
+ field public java.lang.String title;
+ }
+
public class WebHistoryItem implements java.lang.Cloneable {
method public android.graphics.Bitmap getFavicon();
method public java.lang.String getOriginalUrl();
@@ -35849,10 +35807,14 @@
method public boolean getSplitTrack();
method public android.graphics.drawable.Drawable getThumb();
method public int getThumbOffset();
+ method public android.content.res.ColorStateList getThumbTint();
+ method public android.graphics.PorterDuff.Mode getThumbTintMode();
method public void setKeyProgressIncrement(int);
method public void setSplitTrack(boolean);
method public void setThumb(android.graphics.drawable.Drawable);
method public void setThumbOffset(int);
+ method public void setThumbTint(android.content.res.ColorStateList);
+ method public void setThumbTintMode(android.graphics.PorterDuff.Mode);
}
public abstract class AbsSpinner extends android.widget.AdapterView {
@@ -36267,9 +36229,13 @@
ctor public CompoundButton(android.content.Context, android.util.AttributeSet);
ctor public CompoundButton(android.content.Context, android.util.AttributeSet, int);
ctor public CompoundButton(android.content.Context, android.util.AttributeSet, int, int);
+ method public android.content.res.ColorStateList getButtonTint();
+ method public android.graphics.PorterDuff.Mode getButtonTintMode();
method public boolean isChecked();
method public void setButtonDrawable(int);
method public void setButtonDrawable(android.graphics.drawable.Drawable);
+ method public void setButtonTint(android.content.res.ColorStateList);
+ method public void setButtonTintMode(android.graphics.PorterDuff.Mode);
method public void setChecked(boolean);
method public void setOnCheckedChangeListener(android.widget.CompoundButton.OnCheckedChangeListener);
method public void toggle();
@@ -36530,10 +36496,14 @@
method public deprecated boolean getConsiderGoneChildrenWhenMeasuring();
method public android.graphics.drawable.Drawable getForeground();
method public int getForegroundGravity();
+ method public android.content.res.ColorStateList getForegroundTint();
+ 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 setForegroundTint(android.content.res.ColorStateList);
+ method public void setForegroundTintMode(android.graphics.PorterDuff.Mode);
method public void setMeasureAllChildren(boolean);
}
@@ -36742,6 +36712,8 @@
method public int getMaxHeight();
method public int getMaxWidth();
method public android.widget.ImageView.ScaleType getScaleType();
+ method public android.content.res.ColorStateList getTint();
+ method public android.graphics.PorterDuff.Mode getTintMode();
method public int[] onCreateDrawableState(int);
method public void setAdjustViewBounds(boolean);
method public deprecated void setAlpha(int);
@@ -36763,6 +36735,8 @@
method public void setMaxHeight(int);
method public void setMaxWidth(int);
method public void setScaleType(android.widget.ImageView.ScaleType);
+ method public void setTint(android.content.res.ColorStateList);
+ method public void setTintMode(android.graphics.PorterDuff.Mode);
}
public static final class ImageView.ScaleType extends java.lang.Enum {
@@ -37135,11 +37109,19 @@
ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int);
ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int, int);
method public android.graphics.drawable.Drawable getIndeterminateDrawable();
+ method public android.content.res.ColorStateList getIndeterminateTint();
+ method public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
method public android.view.animation.Interpolator getInterpolator();
method public synchronized int getMax();
method public synchronized int getProgress();
+ method public android.content.res.ColorStateList getProgressBackgroundTint();
+ method public android.graphics.PorterDuff.Mode getProgressBackgroundTintMode();
method public android.graphics.drawable.Drawable getProgressDrawable();
+ method public android.content.res.ColorStateList getProgressTint();
+ method public android.graphics.PorterDuff.Mode getProgressTintMode();
method public synchronized int getSecondaryProgress();
+ method public android.content.res.ColorStateList getSecondaryProgressTint();
+ method public android.graphics.PorterDuff.Mode getSecondaryProgressTintMode();
method public final synchronized void incrementProgressBy(int);
method public final synchronized void incrementSecondaryProgressBy(int);
method public synchronized boolean isIndeterminate();
@@ -37148,13 +37130,21 @@
method public synchronized void setIndeterminate(boolean);
method public void setIndeterminateDrawable(android.graphics.drawable.Drawable);
method public void setIndeterminateDrawableTiled(android.graphics.drawable.Drawable);
+ method public void setIndeterminateTint(android.content.res.ColorStateList);
+ method public void setIndeterminateTintMode(android.graphics.PorterDuff.Mode);
method public void setInterpolator(android.content.Context, int);
method public void setInterpolator(android.view.animation.Interpolator);
method public synchronized void setMax(int);
method public synchronized void setProgress(int);
+ method public void setProgressBackgroundTint(android.content.res.ColorStateList);
+ method public void setProgressBackgroundTintMode(android.graphics.PorterDuff.Mode);
method public void setProgressDrawable(android.graphics.drawable.Drawable);
method public void setProgressDrawableTiled(android.graphics.drawable.Drawable);
+ method public void setProgressTint(android.content.res.ColorStateList);
+ method public void setProgressTintMode(android.graphics.PorterDuff.Mode);
method public synchronized void setSecondaryProgress(int);
+ method public void setSecondaryProgressTint(android.content.res.ColorStateList);
+ method public void setSecondaryProgressTintMode(android.graphics.PorterDuff.Mode);
}
public class QuickContactBadge extends android.widget.ImageView implements android.view.View.OnClickListener {
@@ -37889,6 +37879,7 @@
method public float getShadowDx();
method public float getShadowDy();
method public float getShadowRadius();
+ method public final boolean getShowSoftInputOnFocus();
method public java.lang.CharSequence getText();
method public static int getTextColor(android.content.Context, android.content.res.TypedArray, int);
method public final android.content.res.ColorStateList getTextColors();
@@ -37982,6 +37973,7 @@
method public void setScroller(android.widget.Scroller);
method public void setSelectAllOnFocus(boolean);
method public void setShadowLayer(float, float, float, int);
+ method public final void setShowSoftInputOnFocus(boolean);
method public void setSingleLine();
method public void setSingleLine(boolean);
method public final void setSpannableFactory(android.text.Spannable.Factory);
@@ -40147,109 +40139,6 @@
field public static final java.lang.Character.UnicodeBlock YI_SYLLABLES;
}
- public static final class Character.UnicodeScript extends java.lang.Enum {
- method public static java.lang.Character.UnicodeScript forName(java.lang.String);
- method public static java.lang.Character.UnicodeScript of(int);
- method public static java.lang.Character.UnicodeScript valueOf(java.lang.String);
- method public static final java.lang.Character.UnicodeScript[] values();
- enum_constant public static final java.lang.Character.UnicodeScript ARABIC;
- enum_constant public static final java.lang.Character.UnicodeScript ARMENIAN;
- enum_constant public static final java.lang.Character.UnicodeScript AVESTAN;
- enum_constant public static final java.lang.Character.UnicodeScript BALINESE;
- enum_constant public static final java.lang.Character.UnicodeScript BAMUM;
- enum_constant public static final java.lang.Character.UnicodeScript BATAK;
- enum_constant public static final java.lang.Character.UnicodeScript BENGALI;
- enum_constant public static final java.lang.Character.UnicodeScript BOPOMOFO;
- enum_constant public static final java.lang.Character.UnicodeScript BRAHMI;
- enum_constant public static final java.lang.Character.UnicodeScript BRAILLE;
- enum_constant public static final java.lang.Character.UnicodeScript BUGINESE;
- enum_constant public static final java.lang.Character.UnicodeScript BUHID;
- enum_constant public static final java.lang.Character.UnicodeScript CANADIAN_ABORIGINAL;
- enum_constant public static final java.lang.Character.UnicodeScript CARIAN;
- enum_constant public static final java.lang.Character.UnicodeScript CHAM;
- enum_constant public static final java.lang.Character.UnicodeScript CHEROKEE;
- enum_constant public static final java.lang.Character.UnicodeScript COMMON;
- enum_constant public static final java.lang.Character.UnicodeScript COPTIC;
- enum_constant public static final java.lang.Character.UnicodeScript CUNEIFORM;
- enum_constant public static final java.lang.Character.UnicodeScript CYPRIOT;
- enum_constant public static final java.lang.Character.UnicodeScript CYRILLIC;
- enum_constant public static final java.lang.Character.UnicodeScript DESERET;
- enum_constant public static final java.lang.Character.UnicodeScript DEVANAGARI;
- enum_constant public static final java.lang.Character.UnicodeScript EGYPTIAN_HIEROGLYPHS;
- enum_constant public static final java.lang.Character.UnicodeScript ETHIOPIC;
- enum_constant public static final java.lang.Character.UnicodeScript GEORGIAN;
- enum_constant public static final java.lang.Character.UnicodeScript GLAGOLITIC;
- enum_constant public static final java.lang.Character.UnicodeScript GOTHIC;
- enum_constant public static final java.lang.Character.UnicodeScript GREEK;
- enum_constant public static final java.lang.Character.UnicodeScript GUJARATI;
- enum_constant public static final java.lang.Character.UnicodeScript GURMUKHI;
- enum_constant public static final java.lang.Character.UnicodeScript HAN;
- enum_constant public static final java.lang.Character.UnicodeScript HANGUL;
- enum_constant public static final java.lang.Character.UnicodeScript HANUNOO;
- enum_constant public static final java.lang.Character.UnicodeScript HEBREW;
- enum_constant public static final java.lang.Character.UnicodeScript HIRAGANA;
- enum_constant public static final java.lang.Character.UnicodeScript IMPERIAL_ARAMAIC;
- enum_constant public static final java.lang.Character.UnicodeScript INHERITED;
- enum_constant public static final java.lang.Character.UnicodeScript INSCRIPTIONAL_PAHLAVI;
- enum_constant public static final java.lang.Character.UnicodeScript INSCRIPTIONAL_PARTHIAN;
- enum_constant public static final java.lang.Character.UnicodeScript JAVANESE;
- enum_constant public static final java.lang.Character.UnicodeScript KAITHI;
- enum_constant public static final java.lang.Character.UnicodeScript KANNADA;
- enum_constant public static final java.lang.Character.UnicodeScript KATAKANA;
- enum_constant public static final java.lang.Character.UnicodeScript KAYAH_LI;
- enum_constant public static final java.lang.Character.UnicodeScript KHAROSHTHI;
- enum_constant public static final java.lang.Character.UnicodeScript KHMER;
- enum_constant public static final java.lang.Character.UnicodeScript LAO;
- enum_constant public static final java.lang.Character.UnicodeScript LATIN;
- enum_constant public static final java.lang.Character.UnicodeScript LEPCHA;
- enum_constant public static final java.lang.Character.UnicodeScript LIMBU;
- enum_constant public static final java.lang.Character.UnicodeScript LINEAR_B;
- enum_constant public static final java.lang.Character.UnicodeScript LISU;
- enum_constant public static final java.lang.Character.UnicodeScript LYCIAN;
- enum_constant public static final java.lang.Character.UnicodeScript LYDIAN;
- enum_constant public static final java.lang.Character.UnicodeScript MALAYALAM;
- enum_constant public static final java.lang.Character.UnicodeScript MANDAIC;
- enum_constant public static final java.lang.Character.UnicodeScript MEETEI_MAYEK;
- enum_constant public static final java.lang.Character.UnicodeScript MONGOLIAN;
- enum_constant public static final java.lang.Character.UnicodeScript MYANMAR;
- enum_constant public static final java.lang.Character.UnicodeScript NEW_TAI_LUE;
- enum_constant public static final java.lang.Character.UnicodeScript NKO;
- enum_constant public static final java.lang.Character.UnicodeScript OGHAM;
- enum_constant public static final java.lang.Character.UnicodeScript OLD_ITALIC;
- enum_constant public static final java.lang.Character.UnicodeScript OLD_PERSIAN;
- enum_constant public static final java.lang.Character.UnicodeScript OLD_SOUTH_ARABIAN;
- enum_constant public static final java.lang.Character.UnicodeScript OLD_TURKIC;
- enum_constant public static final java.lang.Character.UnicodeScript OL_CHIKI;
- enum_constant public static final java.lang.Character.UnicodeScript ORIYA;
- enum_constant public static final java.lang.Character.UnicodeScript OSMANYA;
- enum_constant public static final java.lang.Character.UnicodeScript PHAGS_PA;
- enum_constant public static final java.lang.Character.UnicodeScript PHOENICIAN;
- enum_constant public static final java.lang.Character.UnicodeScript REJANG;
- enum_constant public static final java.lang.Character.UnicodeScript RUNIC;
- enum_constant public static final java.lang.Character.UnicodeScript SAMARITAN;
- enum_constant public static final java.lang.Character.UnicodeScript SAURASHTRA;
- enum_constant public static final java.lang.Character.UnicodeScript SHAVIAN;
- enum_constant public static final java.lang.Character.UnicodeScript SINHALA;
- enum_constant public static final java.lang.Character.UnicodeScript SUNDANESE;
- enum_constant public static final java.lang.Character.UnicodeScript SYLOTI_NAGRI;
- enum_constant public static final java.lang.Character.UnicodeScript SYRIAC;
- enum_constant public static final java.lang.Character.UnicodeScript TAGALOG;
- enum_constant public static final java.lang.Character.UnicodeScript TAGBANWA;
- enum_constant public static final java.lang.Character.UnicodeScript TAI_LE;
- enum_constant public static final java.lang.Character.UnicodeScript TAI_THAM;
- enum_constant public static final java.lang.Character.UnicodeScript TAI_VIET;
- enum_constant public static final java.lang.Character.UnicodeScript TAMIL;
- enum_constant public static final java.lang.Character.UnicodeScript TELUGU;
- enum_constant public static final java.lang.Character.UnicodeScript THAANA;
- enum_constant public static final java.lang.Character.UnicodeScript THAI;
- enum_constant public static final java.lang.Character.UnicodeScript TIBETAN;
- enum_constant public static final java.lang.Character.UnicodeScript TIFINAGH;
- enum_constant public static final java.lang.Character.UnicodeScript UGARITIC;
- enum_constant public static final java.lang.Character.UnicodeScript UNKNOWN;
- enum_constant public static final java.lang.Character.UnicodeScript VAI;
- enum_constant public static final java.lang.Character.UnicodeScript YI;
- }
-
public final class Class implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type {
method public java.lang.Class<? extends U> asSubclass(java.lang.Class<U>);
method public T cast(java.lang.Object);
@@ -42090,13 +41979,11 @@
method public java.lang.String getValue();
method public int getVersion();
method public boolean hasExpired();
- method public boolean isHttpOnly();
method public static java.util.List<java.net.HttpCookie> parse(java.lang.String);
method public void setComment(java.lang.String);
method public void setCommentURL(java.lang.String);
method public void setDiscard(boolean);
method public void setDomain(java.lang.String);
- method public void setHttpOnly(boolean);
method public void setMaxAge(long);
method public void setPath(java.lang.String);
method public void setPortlist(java.lang.String);
@@ -42487,11 +42374,6 @@
method public abstract java.net.SocketImpl createSocketImpl();
}
- public abstract interface SocketOption {
- method public abstract java.lang.String name();
- method public abstract java.lang.Class<T> type();
- }
-
public abstract interface SocketOptions {
method public abstract java.lang.Object getOption(int) throws java.net.SocketException;
method public abstract void setOption(int, java.lang.Object) throws java.net.SocketException;
@@ -42522,21 +42404,6 @@
ctor public SocketTimeoutException(java.lang.String);
}
- public final class StandardSocketOptions {
- ctor public StandardSocketOptions();
- field public static final java.net.SocketOption IP_MULTICAST_IF;
- field public static final java.net.SocketOption IP_MULTICAST_LOOP;
- field public static final java.net.SocketOption IP_MULTICAST_TTL;
- field public static final java.net.SocketOption IP_TOS;
- field public static final java.net.SocketOption SO_BROADCAST;
- field public static final java.net.SocketOption SO_KEEPALIVE;
- field public static final java.net.SocketOption SO_LINGER;
- field public static final java.net.SocketOption SO_RCVBUF;
- field public static final java.net.SocketOption SO_REUSEADDR;
- field public static final java.net.SocketOption SO_SNDBUF;
- field public static final java.net.SocketOption TCP_NODELAY;
- }
-
public final class URI implements java.lang.Comparable java.io.Serializable {
ctor public URI(java.lang.String) throws java.net.URISyntaxException;
ctor public URI(java.lang.String, java.lang.String, java.lang.String) throws java.net.URISyntaxException;
@@ -42632,7 +42499,6 @@
method public java.lang.Object getContent(java.lang.Class[]) throws java.io.IOException;
method public java.lang.String getContentEncoding();
method public int getContentLength();
- method public long getContentLengthLong();
method public java.lang.String getContentType();
method public long getDate();
method public static boolean getDefaultAllowUserInteraction();
@@ -42647,7 +42513,6 @@
method public long getHeaderFieldDate(java.lang.String, long);
method public int getHeaderFieldInt(java.lang.String, int);
method public java.lang.String getHeaderFieldKey(int);
- method public long getHeaderFieldLong(java.lang.String, long);
method public java.util.Map<java.lang.String, java.util.List<java.lang.String>> getHeaderFields();
method public long getIfModifiedSince();
method public java.io.InputStream getInputStream() throws java.io.IOException;
@@ -42998,10 +42863,6 @@
package java.nio.channels {
- public class AlreadyBoundException extends java.lang.IllegalStateException {
- ctor public AlreadyBoundException();
- }
-
public class AlreadyConnectedException extends java.lang.IllegalStateException {
ctor public AlreadyConnectedException();
}
@@ -43049,32 +42910,25 @@
ctor public ConnectionPendingException();
}
- public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.MulticastChannel java.nio.channels.ScatteringByteChannel {
+ public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider);
- method public java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.nio.channels.DatagramChannel disconnect() throws java.io.IOException;
- method public java.net.SocketAddress getLocalAddress() throws java.io.IOException;
- method public T getOption(java.net.SocketOption<T>) throws java.io.IOException;
method public abstract boolean isConnected();
- method public java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
- method public java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
method public static java.nio.channels.DatagramChannel open() throws java.io.IOException;
method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
method public final synchronized long read(java.nio.ByteBuffer[]) throws java.io.IOException;
method public abstract java.net.SocketAddress receive(java.nio.ByteBuffer) throws java.io.IOException;
method public abstract int send(java.nio.ByteBuffer, java.net.SocketAddress) throws java.io.IOException;
- method public java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
method public abstract java.net.DatagramSocket socket();
- method public java.util.Set<java.net.SocketOption<?>> supportedOptions();
method public final int validOps();
method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
method public abstract long write(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
method public final synchronized long write(java.nio.ByteBuffer[]) throws java.io.IOException;
}
- public abstract class FileChannel extends java.nio.channels.spi.AbstractInterruptibleChannel implements java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel java.nio.channels.SeekableByteChannel {
+ public abstract class FileChannel extends java.nio.channels.spi.AbstractInterruptibleChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
ctor protected FileChannel();
method public abstract void force(boolean) throws java.io.IOException;
method public final java.nio.channels.FileLock lock() throws java.io.IOException;
@@ -43106,7 +42960,6 @@
public abstract class FileLock implements java.lang.AutoCloseable {
ctor protected FileLock(java.nio.channels.FileChannel, long, long, boolean);
- method public java.nio.channels.Channel acquiredBy();
method public final java.nio.channels.FileChannel channel();
method public final void close() throws java.io.IOException;
method public final boolean isShared();
@@ -43139,32 +42992,6 @@
method public abstract void close() throws java.io.IOException;
}
- public abstract class MembershipKey {
- ctor protected MembershipKey();
- method public abstract java.nio.channels.MembershipKey block(java.net.InetAddress) throws java.io.IOException;
- method public abstract java.nio.channels.MulticastChannel channel();
- method public abstract void drop();
- method public abstract java.net.InetAddress group();
- method public abstract boolean isValid();
- method public abstract java.net.NetworkInterface networkInterface();
- method public abstract java.net.InetAddress sourceAddress();
- method public abstract java.nio.channels.MembershipKey unblock(java.net.InetAddress);
- }
-
- public abstract interface MulticastChannel implements java.nio.channels.NetworkChannel {
- method public abstract void close() throws java.io.IOException;
- method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
- method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
- }
-
- public abstract interface NetworkChannel implements java.lang.AutoCloseable java.nio.channels.Channel java.io.Closeable {
- method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
- method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
- method public abstract T getOption(java.net.SocketOption<T>) throws java.io.IOException;
- method public abstract java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
- method public abstract java.util.Set<java.net.SocketOption<?>> supportedOptions();
- }
-
public class NoConnectionPendingException extends java.lang.IllegalStateException {
ctor public NoConnectionPendingException();
}
@@ -43215,15 +43042,6 @@
method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
}
- public abstract interface SeekableByteChannel implements java.nio.channels.ByteChannel {
- method public abstract long position() throws java.io.IOException;
- method public abstract java.nio.channels.SeekableByteChannel position(long) throws java.io.IOException;
- method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
- method public abstract long size() throws java.io.IOException;
- method public abstract java.nio.channels.SeekableByteChannel truncate(long) throws java.io.IOException;
- method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
- }
-
public abstract class SelectableChannel extends java.nio.channels.spi.AbstractInterruptibleChannel implements java.nio.channels.Channel {
ctor protected SelectableChannel();
method public abstract java.lang.Object blockingLock();
@@ -43272,27 +43090,18 @@
method public abstract java.nio.channels.Selector wakeup();
}
- public abstract class ServerSocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.NetworkChannel {
+ public abstract class ServerSocketChannel extends java.nio.channels.spi.AbstractSelectableChannel {
ctor protected ServerSocketChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.SocketChannel accept() throws java.io.IOException;
- method public final java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
- method public java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException;
- method public java.net.SocketAddress getLocalAddress() throws java.io.IOException;
- method public T getOption(java.net.SocketOption<T>) throws java.io.IOException;
method public static java.nio.channels.ServerSocketChannel open() throws java.io.IOException;
- method public java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
method public abstract java.net.ServerSocket socket();
- method public java.util.Set<java.net.SocketOption<?>> supportedOptions();
method public final int validOps();
}
- public abstract class SocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel {
+ public abstract class SocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
ctor protected SocketChannel(java.nio.channels.spi.SelectorProvider);
- method public java.nio.channels.SocketChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract boolean connect(java.net.SocketAddress) throws java.io.IOException;
method public abstract boolean finishConnect() throws java.io.IOException;
- method public java.net.SocketAddress getLocalAddress() throws java.io.IOException;
- method public T getOption(java.net.SocketOption<T>) throws java.io.IOException;
method public abstract boolean isConnected();
method public abstract boolean isConnectionPending();
method public static java.nio.channels.SocketChannel open() throws java.io.IOException;
@@ -43300,9 +43109,7 @@
method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
method public final synchronized long read(java.nio.ByteBuffer[]) throws java.io.IOException;
- method public java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException;
method public abstract java.net.Socket socket();
- method public java.util.Set<java.net.SocketOption<?>> supportedOptions();
method public final int validOps();
method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException;
method public abstract long write(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
@@ -47262,7 +47069,6 @@
method public java.lang.String getDisplayName(java.util.Locale);
method public static java.util.Currency getInstance(java.lang.String);
method public static java.util.Currency getInstance(java.util.Locale);
- method public int getNumericCode();
method public java.lang.String getSymbol();
method public java.lang.String getSymbol(java.util.Locale);
}
@@ -47547,13 +47353,6 @@
method public int getWidth();
}
- public class IllformedLocaleException extends java.lang.RuntimeException {
- ctor public IllformedLocaleException();
- ctor public IllformedLocaleException(java.lang.String);
- ctor public IllformedLocaleException(java.lang.String, int);
- method public int getErrorIndex();
- }
-
public class InputMismatchException extends java.util.NoSuchElementException implements java.io.Serializable {
ctor public InputMismatchException();
ctor public InputMismatchException(java.lang.String);
@@ -47668,7 +47467,6 @@
ctor public Locale(java.lang.String, java.lang.String);
ctor public Locale(java.lang.String, java.lang.String, java.lang.String);
method public java.lang.Object clone();
- method public static java.util.Locale forLanguageTag(java.lang.String);
method public static java.util.Locale[] getAvailableLocales();
method public java.lang.String getCountry();
method public static java.util.Locale getDefault();
@@ -47678,24 +47476,15 @@
method public java.lang.String getDisplayLanguage(java.util.Locale);
method public final java.lang.String getDisplayName();
method public java.lang.String getDisplayName(java.util.Locale);
- method public java.lang.String getDisplayScript();
- method public java.lang.String getDisplayScript(java.util.Locale);
method public final java.lang.String getDisplayVariant();
method public java.lang.String getDisplayVariant(java.util.Locale);
- method public java.lang.String getExtension(char);
- method public java.util.Set<java.lang.Character> getExtensionKeys();
method public java.lang.String getISO3Country();
method public java.lang.String getISO3Language();
method public static java.lang.String[] getISOCountries();
method public static java.lang.String[] getISOLanguages();
method public java.lang.String getLanguage();
- method public java.lang.String getScript();
- method public java.util.Set<java.lang.String> getUnicodeLocaleAttributes();
- method public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
- method public java.lang.String getUnicodeLocaleType(java.lang.String);
method public java.lang.String getVariant();
method public static synchronized void setDefault(java.util.Locale);
- method public java.lang.String toLanguageTag();
method public final java.lang.String toString();
field public static final java.util.Locale CANADA;
field public static final java.util.Locale CANADA_FRENCH;
@@ -47713,33 +47502,14 @@
field public static final java.util.Locale KOREA;
field public static final java.util.Locale KOREAN;
field public static final java.util.Locale PRC;
- field public static final char PRIVATE_USE_EXTENSION = 120; // 0x0078 'x'
field public static final java.util.Locale ROOT;
field public static final java.util.Locale SIMPLIFIED_CHINESE;
field public static final java.util.Locale TAIWAN;
field public static final java.util.Locale TRADITIONAL_CHINESE;
field public static final java.util.Locale UK;
- field public static final char UNICODE_LOCALE_EXTENSION = 117; // 0x0075 'u'
field public static final java.util.Locale US;
}
- public static final class Locale.Builder {
- ctor public Locale.Builder();
- method public java.util.Locale.Builder addUnicodeLocaleAttribute(java.lang.String);
- method public java.util.Locale build();
- method public java.util.Locale.Builder clear();
- method public java.util.Locale.Builder clearExtensions();
- method public java.util.Locale.Builder removeUnicodeLocaleAttribute(java.lang.String);
- method public java.util.Locale.Builder setExtension(char, java.lang.String);
- method public java.util.Locale.Builder setLanguage(java.lang.String);
- method public java.util.Locale.Builder setLanguageTag(java.lang.String);
- method public java.util.Locale.Builder setLocale(java.util.Locale);
- method public java.util.Locale.Builder setRegion(java.lang.String);
- method public java.util.Locale.Builder setScript(java.lang.String);
- method public java.util.Locale.Builder setUnicodeLocaleKeyword(java.lang.String, java.lang.String);
- method public java.util.Locale.Builder setVariant(java.lang.String);
- }
-
public abstract interface Map {
method public abstract void clear();
method public abstract boolean containsKey(java.lang.Object);
@@ -48426,35 +48196,6 @@
method public V replace(K, V);
}
- public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable {
- ctor public ConcurrentLinkedDeque();
- ctor public ConcurrentLinkedDeque(java.util.Collection<? extends E>);
- method public void addFirst(E);
- method public void addLast(E);
- method public java.util.Iterator<E> descendingIterator();
- method public E element();
- method public E getFirst();
- method public E getLast();
- method public java.util.Iterator<E> iterator();
- method public boolean offer(E);
- method public boolean offerFirst(E);
- method public boolean offerLast(E);
- method public E peek();
- method public E peekFirst();
- method public E peekLast();
- method public E poll();
- method public E pollFirst();
- method public E pollLast();
- method public E pop();
- method public void push(E);
- method public E remove();
- method public E removeFirst();
- method public boolean removeFirstOccurrence(java.lang.Object);
- method public E removeLast();
- method public boolean removeLastOccurrence(java.lang.Object);
- method public int size();
- }
-
public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable {
ctor public ConcurrentLinkedQueue();
ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>);
@@ -48695,94 +48436,6 @@
method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService);
}
- public class ForkJoinPool extends java.util.concurrent.AbstractExecutorService {
- ctor public ForkJoinPool();
- ctor public ForkJoinPool(int);
- ctor public ForkJoinPool(int, java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory, java.lang.Thread.UncaughtExceptionHandler, boolean);
- method public boolean awaitQuiescence(long, java.util.concurrent.TimeUnit);
- method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
- method protected int drainTasksTo(java.util.Collection<? super java.util.concurrent.ForkJoinTask<?>>);
- method public void execute(java.util.concurrent.ForkJoinTask<?>);
- method public void execute(java.lang.Runnable);
- method public int getActiveThreadCount();
- method public boolean getAsyncMode();
- method public java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory getFactory();
- method public int getParallelism();
- method public int getPoolSize();
- method public int getQueuedSubmissionCount();
- method public long getQueuedTaskCount();
- method public int getRunningThreadCount();
- method public long getStealCount();
- method public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
- method public boolean hasQueuedSubmissions();
- method public T invoke(java.util.concurrent.ForkJoinTask<T>);
- method public boolean isQuiescent();
- method public boolean isShutdown();
- method public boolean isTerminated();
- method public boolean isTerminating();
- method public static void managedBlock(java.util.concurrent.ForkJoinPool.ManagedBlocker) throws java.lang.InterruptedException;
- method protected java.util.concurrent.ForkJoinTask<?> pollSubmission();
- method public void shutdown();
- method public java.util.List<java.lang.Runnable> shutdownNow();
- method public java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>);
- field public static final java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory;
- }
-
- public static abstract interface ForkJoinPool.ForkJoinWorkerThreadFactory {
- method public abstract java.util.concurrent.ForkJoinWorkerThread newThread(java.util.concurrent.ForkJoinPool);
- }
-
- public static abstract interface ForkJoinPool.ManagedBlocker {
- method public abstract boolean block() throws java.lang.InterruptedException;
- method public abstract boolean isReleasable();
- }
-
- public abstract class ForkJoinTask implements java.util.concurrent.Future java.io.Serializable {
- ctor public ForkJoinTask();
- method public static java.util.concurrent.ForkJoinTask<?> adapt(java.lang.Runnable);
- method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T);
- method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>);
- method public boolean cancel(boolean);
- method public void complete(V);
- method public void completeExceptionally(java.lang.Throwable);
- method protected abstract boolean exec();
- method public final java.util.concurrent.ForkJoinTask<V> fork();
- method public final V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
- method public final V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
- method public final java.lang.Throwable getException();
- method public static java.util.concurrent.ForkJoinPool getPool();
- method public static int getQueuedTaskCount();
- method public abstract V getRawResult();
- method public static int getSurplusQueuedTaskCount();
- method public static void helpQuiesce();
- method public static boolean inForkJoinPool();
- method public final V invoke();
- method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>, java.util.concurrent.ForkJoinTask<?>);
- method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>...);
- method public static java.util.Collection<T> invokeAll(java.util.Collection<T>);
- method public final boolean isCancelled();
- method public final boolean isCompletedAbnormally();
- method public final boolean isCompletedNormally();
- method public final boolean isDone();
- method public final V join();
- method protected static java.util.concurrent.ForkJoinTask<?> peekNextLocalTask();
- method protected static java.util.concurrent.ForkJoinTask<?> pollNextLocalTask();
- method protected static java.util.concurrent.ForkJoinTask<?> pollTask();
- method public final void quietlyInvoke();
- method public final void quietlyJoin();
- method public void reinitialize();
- method protected abstract void setRawResult(V);
- method public boolean tryUnfork();
- }
-
- public class ForkJoinWorkerThread extends java.lang.Thread {
- ctor protected ForkJoinWorkerThread(java.util.concurrent.ForkJoinPool);
- method public java.util.concurrent.ForkJoinPool getPool();
- method public int getPoolIndex();
- method protected void onStart();
- method protected void onTermination(java.lang.Throwable);
- }
-
public abstract interface Future {
method public abstract boolean cancel(boolean);
method public abstract V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
@@ -48867,52 +48520,6 @@
method public E take() throws java.lang.InterruptedException;
}
- public class LinkedTransferQueue extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue {
- ctor public LinkedTransferQueue();
- ctor public LinkedTransferQueue(java.util.Collection<? extends E>);
- method public int drainTo(java.util.Collection<? super E>);
- method public int drainTo(java.util.Collection<? super E>, int);
- method public int getWaitingConsumerCount();
- method public boolean hasWaitingConsumer();
- method public java.util.Iterator<E> iterator();
- method public boolean offer(E, long, java.util.concurrent.TimeUnit);
- method public boolean offer(E);
- method public E peek();
- method public E poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
- method public E poll();
- method public void put(E);
- method public int remainingCapacity();
- method public int size();
- method public E take() throws java.lang.InterruptedException;
- method public void transfer(E) throws java.lang.InterruptedException;
- method public boolean tryTransfer(E);
- method public boolean tryTransfer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
- }
-
- public class Phaser {
- ctor public Phaser();
- ctor public Phaser(int);
- ctor public Phaser(java.util.concurrent.Phaser);
- ctor public Phaser(java.util.concurrent.Phaser, int);
- method public int arrive();
- method public int arriveAndAwaitAdvance();
- method public int arriveAndDeregister();
- method public int awaitAdvance(int);
- method public int awaitAdvanceInterruptibly(int) throws java.lang.InterruptedException;
- method public int awaitAdvanceInterruptibly(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
- method public int bulkRegister(int);
- method public void forceTermination();
- method public int getArrivedParties();
- method public java.util.concurrent.Phaser getParent();
- method public final int getPhase();
- method public int getRegisteredParties();
- method public java.util.concurrent.Phaser getRoot();
- method public int getUnarrivedParties();
- method public boolean isTerminated();
- method protected boolean onAdvance(int, int);
- method public int register();
- }
-
public class PriorityBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable {
ctor public PriorityBlockingQueue();
ctor public PriorityBlockingQueue(int);
@@ -48933,22 +48540,6 @@
method public E take() throws java.lang.InterruptedException;
}
- public abstract class RecursiveAction extends java.util.concurrent.ForkJoinTask {
- ctor public RecursiveAction();
- method protected abstract void compute();
- method protected final boolean exec();
- method public final java.lang.Void getRawResult();
- method protected final void setRawResult(java.lang.Void);
- }
-
- public abstract class RecursiveTask extends java.util.concurrent.ForkJoinTask {
- ctor public RecursiveTask();
- method protected abstract V compute();
- method protected final boolean exec();
- method public final V getRawResult();
- method protected final void setRawResult(V);
- }
-
public class RejectedExecutionException extends java.lang.RuntimeException {
ctor public RejectedExecutionException();
ctor public RejectedExecutionException(java.lang.String);
@@ -48987,14 +48578,12 @@
method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>);
method public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy();
method public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy();
- method public boolean getRemoveOnCancelPolicy();
method public java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit);
method public java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit);
method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit);
method public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean);
method public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean);
- method public void setRemoveOnCancelPolicy(boolean);
}
public class Semaphore implements java.io.Serializable {
@@ -49040,15 +48629,6 @@
method public abstract java.lang.Thread newThread(java.lang.Runnable);
}
- public class ThreadLocalRandom extends java.util.Random {
- method public static java.util.concurrent.ThreadLocalRandom current();
- method public double nextDouble(double);
- method public double nextDouble(double, double);
- method public int nextInt(int, int);
- method public long nextLong(long);
- method public long nextLong(long, long);
- }
-
public class ThreadPoolExecutor extends java.util.concurrent.AbstractExecutorService {
ctor public ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue<java.lang.Runnable>);
ctor public ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue<java.lang.Runnable>, java.util.concurrent.ThreadFactory);
@@ -49136,14 +48716,6 @@
ctor public TimeoutException(java.lang.String);
}
- public abstract interface TransferQueue implements java.util.concurrent.BlockingQueue {
- method public abstract int getWaitingConsumerCount();
- method public abstract boolean hasWaitingConsumer();
- method public abstract void transfer(E) throws java.lang.InterruptedException;
- method public abstract boolean tryTransfer(E);
- method public abstract boolean tryTransfer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException;
- }
-
}
package java.util.concurrent.atomic {
@@ -49353,7 +48925,6 @@
method public final int getWaitQueueLength(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject);
method public final java.util.Collection<java.lang.Thread> getWaitingThreads(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject);
method public final boolean hasContended();
- method public final boolean hasQueuedPredecessors();
method public final boolean hasQueuedThreads();
method public final boolean hasWaiters(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject);
method protected boolean isHeldExclusively();
@@ -49400,7 +48971,6 @@
method public final int getWaitQueueLength(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject);
method public final java.util.Collection<java.lang.Thread> getWaitingThreads(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject);
method public final boolean hasContended();
- method public final boolean hasQueuedPredecessors();
method public final boolean hasQueuedThreads();
method public final boolean hasWaiters(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject);
method protected boolean isHeldExclusively();
@@ -50345,10 +49915,8 @@
public class ZipFile implements java.io.Closeable {
ctor public ZipFile(java.io.File) throws java.io.IOException, java.util.zip.ZipException;
- ctor public ZipFile(java.io.File, java.nio.charset.Charset) throws java.io.IOException, java.util.zip.ZipException;
ctor public ZipFile(java.lang.String) throws java.io.IOException;
ctor public ZipFile(java.io.File, int) throws java.io.IOException;
- ctor public ZipFile(java.io.File, int, java.nio.charset.Charset) throws java.io.IOException;
method public void close() throws java.io.IOException;
method public java.util.Enumeration<? extends java.util.zip.ZipEntry> entries();
method public java.lang.String getComment();
@@ -50402,7 +49970,6 @@
public class ZipInputStream extends java.util.zip.InflaterInputStream {
ctor public ZipInputStream(java.io.InputStream);
- ctor public ZipInputStream(java.io.InputStream, java.nio.charset.Charset);
method public void closeEntry() throws java.io.IOException;
method protected java.util.zip.ZipEntry createZipEntry(java.lang.String);
method public java.util.zip.ZipEntry getNextEntry() throws java.io.IOException;
@@ -50450,7 +50017,6 @@
public class ZipOutputStream extends java.util.zip.DeflaterOutputStream {
ctor public ZipOutputStream(java.io.OutputStream);
- ctor public ZipOutputStream(java.io.OutputStream, java.nio.charset.Charset);
method public void closeEntry() throws java.io.IOException;
method public void putNextEntry(java.util.zip.ZipEntry) throws java.io.IOException;
method public void setComment(java.lang.String);
@@ -51949,7 +51515,6 @@
method public abstract boolean getEnableSessionCreation();
method public abstract java.lang.String[] getEnabledCipherSuites();
method public abstract java.lang.String[] getEnabledProtocols();
- method public javax.net.ssl.SSLSession getHandshakeSession();
method public abstract javax.net.ssl.SSLEngineResult.HandshakeStatus getHandshakeStatus();
method public abstract boolean getNeedClientAuth();
method public java.lang.String getPeerHost();
@@ -52023,12 +51588,10 @@
ctor public SSLParameters(java.lang.String[]);
ctor public SSLParameters(java.lang.String[], java.lang.String[]);
method public java.lang.String[] getCipherSuites();
- method public java.lang.String getEndpointIdentificationAlgorithm();
method public boolean getNeedClientAuth();
method public java.lang.String[] getProtocols();
method public boolean getWantClientAuth();
method public void setCipherSuites(java.lang.String[]);
- method public void setEndpointIdentificationAlgorithm(java.lang.String);
method public void setNeedClientAuth(boolean);
method public void setProtocols(java.lang.String[]);
method public void setWantClientAuth(boolean);
@@ -52129,7 +51692,6 @@
method public abstract boolean getEnableSessionCreation();
method public abstract java.lang.String[] getEnabledCipherSuites();
method public abstract java.lang.String[] getEnabledProtocols();
- method public javax.net.ssl.SSLSession getHandshakeSession();
method public abstract boolean getNeedClientAuth();
method public javax.net.ssl.SSLParameters getSSLParameters();
method public abstract javax.net.ssl.SSLSession getSession();
@@ -52185,14 +51747,6 @@
method public java.lang.String chooseEngineServerAlias(java.lang.String, java.security.Principal[], javax.net.ssl.SSLEngine);
}
- public abstract class X509ExtendedTrustManager implements javax.net.ssl.X509TrustManager {
- ctor public X509ExtendedTrustManager();
- method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String, java.net.Socket) throws java.security.cert.CertificateException;
- method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
- method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, java.net.Socket) throws java.security.cert.CertificateException;
- method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException;
- }
-
public abstract interface X509KeyManager implements javax.net.ssl.KeyManager {
method public abstract java.lang.String chooseClientAlias(java.lang.String[], java.security.Principal[], java.net.Socket);
method public abstract java.lang.String chooseServerAlias(java.lang.String, java.security.Principal[], java.net.Socket);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 8945526..127b0fc 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -32,6 +32,7 @@
import android.content.Intent;
import android.content.pm.IPackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
@@ -43,8 +44,11 @@
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.AndroidException;
import android.view.IWindowManager;
+import android.view.View;
+
import com.android.internal.os.BaseCommand;
import dalvik.system.VMRuntime;
@@ -123,6 +127,7 @@
" am stack info <STACK_ID>\n" +
" am lock-task <TASK_ID>\n" +
" am lock-task stop\n" +
+ " am get-config\n" +
"\n" +
"am start: start an Activity. Options are:\n" +
" -D: enable debugging\n" +
@@ -229,6 +234,9 @@
"\n" +
"am lock-task: bring <TASK_ID> to the front and don't allow other tasks to run\n" +
"\n" +
+ "am get-config: retrieve the configuration and any recent configurations\n" +
+ " of the device\n" +
+ "\n" +
"<INTENT> specifications include these flags and arguments:\n" +
" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
" [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
@@ -323,6 +331,8 @@
runStack();
} else if (op.equals("lock-task")) {
runLockTask();
+ } else if (op.equals("get-config")) {
+ runGetConfig();
} else {
showError("Error: unknown command '" + op + "'");
}
@@ -909,8 +919,7 @@
}
}
- if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId,
- abi)) {
+ if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId, abi)) {
throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
}
@@ -1699,4 +1708,19 @@
} catch (RemoteException e) {
}
}
+
+ private void runGetConfig() throws Exception {
+ try {
+ Configuration config = mAm.getConfiguration();
+ if (config == null) {
+ System.err.println("Activity manager has no configuration");
+ return;
+ }
+
+ System.out.println("config: " + Configuration.resourceQualifierString(config));
+ System.out.println("abi: " + TextUtils.join(",", Build.SUPPORTED_ABIS));
+
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index db3d8bb..d1bea2e 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -23,6 +23,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
+import java.util.ArrayList;
import java.util.HashSet;
public final class Bmgr {
@@ -102,6 +103,11 @@
return;
}
+ if ("fullbackup".equals(op)) {
+ doFullTransportBackup();
+ return;
+ }
+
System.err.println("Unknown command");
showUsage();
}
@@ -165,6 +171,21 @@
}
}
+ private void doFullTransportBackup() {
+ System.out.println("Performing full transport backup");
+
+ String pkg;
+ while ((pkg = nextArg()) != null) {
+ System.out.println(" Package " + pkg + " ...");
+ try {
+ mBmgr.fullTransportBackup(new String[] { pkg });
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ }
+ }
+ }
+
private void doTransport() {
try {
String which = nextArg();
diff --git a/cmds/bu/src/com/android/commands/bu/Backup.java b/cmds/bu/src/com/android/commands/bu/Backup.java
index 4503726..ffc0f87 100644
--- a/cmds/bu/src/com/android/commands/bu/Backup.java
+++ b/cmds/bu/src/com/android/commands/bu/Backup.java
@@ -69,6 +69,7 @@
boolean doEverything = false;
boolean doWidgets = false;
boolean allIncludesSystem = true;
+ boolean doCompress = true;
String arg;
while ((arg = nextArg()) != null) {
@@ -95,6 +96,10 @@
doWidgets = false;
} else if ("-all".equals(arg)) {
doEverything = true;
+ } else if ("-compress".equals(arg)) {
+ doCompress = true;
+ } else if ("-nocompress".equals(arg)) {
+ doCompress = false;
} else {
Log.w(TAG, "Unknown backup flag " + arg);
continue;
@@ -119,7 +124,7 @@
fd = ParcelFileDescriptor.adoptFd(socketFd);
String[] packArray = new String[packages.size()];
mBackupManager.fullBackup(fd, saveApks, saveObbs, saveShared, doWidgets,
- doEverything, allIncludesSystem, packages.toArray(packArray));
+ doEverything, allIncludesSystem, doCompress, packages.toArray(packArray));
} catch (RemoteException e) {
Log.e(TAG, "Unable to invoke backup manager for backup");
} finally {
diff --git a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
index dce0a75..e6847a9 100644
--- a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
+++ b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
@@ -20,6 +20,7 @@
import android.app.IActivityManager;
import android.app.IActivityManager.ContentProviderHolder;
import android.content.IContentProvider;
+import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -33,7 +34,8 @@
enum CommandVerb {
UNSPECIFIED,
GET,
- PUT
+ PUT,
+ DELETE
}
static String[] mArgs;
@@ -74,6 +76,8 @@
mVerb = CommandVerb.GET;
} else if ("put".equalsIgnoreCase(arg)) {
mVerb = CommandVerb.PUT;
+ } else if ("delete".equalsIgnoreCase(arg)) {
+ mVerb = CommandVerb.DELETE;
} else {
// invalid
System.err.println("Invalid command: " + arg);
@@ -87,7 +91,7 @@
break; // invalid
}
mTable = arg.toLowerCase();
- } else if (mVerb == CommandVerb.GET) {
+ } else if (mVerb == CommandVerb.GET || mVerb == CommandVerb.DELETE) {
mKey = arg;
if (mNextArg >= mArgs.length) {
valid = true;
@@ -136,6 +140,10 @@
case PUT:
putForUser(provider, mUser, mTable, mKey, mValue);
break;
+ case DELETE:
+ System.out.println("Deleted "
+ + deleteForUser(provider, mUser, mTable, mKey) + " rows");
+ break;
default:
System.err.println("Unspecified command");
break;
@@ -211,9 +219,31 @@
}
}
+ int deleteForUser(IContentProvider provider, int userHandle,
+ final String table, final String key) {
+ Uri targetUri;
+ if ("system".equals(table)) targetUri = Settings.System.getUriFor(key);
+ else if ("secure".equals(table)) targetUri = Settings.Secure.getUriFor(key);
+ else if ("global".equals(table)) targetUri = Settings.Global.getUriFor(key);
+ else {
+ System.err.println("Invalid table; no delete performed");
+ throw new IllegalArgumentException("Invalid table " + table);
+ }
+
+ int num = 0;
+ try {
+ num = provider.delete(null, targetUri, null, null);
+ } catch (RemoteException e) {
+ System.err.println("Can't clear key " + key + " in " + table + " for user "
+ + userHandle);
+ }
+ return num;
+ }
+
private static void printUsage() {
System.err.println("usage: settings [--user NUM] get namespace key");
System.err.println(" settings [--user NUM] put namespace key value");
+ System.err.println(" settings [--user NUM] delete namespace key");
System.err.println("\n'namespace' is one of {system, secure, global}, case-insensitive");
System.err.println("If '--user NUM' is not given, the operations are performed on the owner user.");
}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 2620c44..cbc8150 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -462,7 +462,9 @@
* anything behind it, then only the modal window will be reported
* (assuming it is the top one). For convenience the returned windows
* are ordered in a descending layer order, which is the windows that
- * are higher in the Z-order are reported first.
+ * are higher in the Z-order are reported first. Since the user can always
+ * interact with the window that has input focus by typing, the focused
+ * window is always returned (even if covered by a modal window).
* <p>
* <strong>Note:</strong> In order to access the windows your service has
* to declare the capability to retrieve window content by setting the
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 4f9ba59..4edb0c6 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -286,8 +286,8 @@
/**
* This flag indicates to the system that the accessibility service wants
* to access content of all interactive windows. An interactive window is a
- * window that can be touched by a sighted user when explore by touch is not
- * enabled. If this flag is not set your service will not receive
+ * window that has input focus or can be touched by a sighted user when explore
+ * by touch is not enabled. If this flag is not set your service will not receive
* {@link android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED}
* events, calling AccessibilityService{@link AccessibilityService#getWindows()
* AccessibilityService.getWindows()} will return an empty list, and {@link
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 12fcdcf..806a55b 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -359,7 +359,29 @@
*/
public AuthenticatorDescription[] getAuthenticatorTypes() {
try {
- return mService.getAuthenticatorTypes();
+ return mService.getAuthenticatorTypes(UserHandle.getCallingUserId());
+ } catch (RemoteException e) {
+ // will never happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * @hide
+ * Lists the currently registered authenticators for a given user id.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>The caller has to be in the same user or have the permission
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+ *
+ * @return An array of {@link AuthenticatorDescription} for every
+ * authenticator known to the AccountManager service. Empty (never
+ * null) if no authenticators are known.
+ */
+ public AuthenticatorDescription[] getAuthenticatorTypesAsUser(int userId) {
+ try {
+ return mService.getAuthenticatorTypes(userId);
} catch (RemoteException e) {
// will never happen
throw new RuntimeException(e);
@@ -389,6 +411,28 @@
/**
* @hide
+ * Lists all accounts of any type registered on the device for a given
+ * user id. Equivalent to getAccountsByType(null).
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#GET_ACCOUNTS}.
+ *
+ * @return An array of {@link Account}, one for each account. Empty
+ * (never null) if no accounts have been added.
+ */
+ public Account[] getAccountsAsUser(int userId) {
+ try {
+ return mService.getAccountsAsUser(null, userId);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * @hide
* For use by internal activities. Returns the list of accounts that the calling package
* is authorized to use, particularly for shared accounts.
* @param packageName package name of the calling app.
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 86e279f..1373dc8 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -29,7 +29,7 @@
interface IAccountManager {
String getPassword(in Account account);
String getUserData(in Account account, String key);
- AuthenticatorDescription[] getAuthenticatorTypes();
+ AuthenticatorDescription[] getAuthenticatorTypes(int userId);
Account[] getAccounts(String accountType);
Account[] getAccountsForPackage(String packageName, int uid);
Account[] getAccountsByTypeForPackage(String type, String packageName);
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 933135d..06f5aca 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -17,6 +17,7 @@
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.content.res.Resources.NotFoundException;
@@ -25,6 +26,9 @@
import android.util.TypedValue;
import android.util.Xml;
import android.view.animation.AnimationUtils;
+
+import com.android.internal.R;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -66,11 +70,26 @@
*/
public static Animator loadAnimator(Context context, int id)
throws NotFoundException {
+ return loadAnimator(context.getResources(), context.getTheme(), id);
+ }
+
+ /**
+ * Loads an {@link Animator} object from a resource
+ *
+ * @param resources The resources
+ * @param theme The theme
+ * @param id The resource id of the animation to load
+ * @return The animator object reference by the specified id
+ * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded
+ * @hide
+ */
+ public static Animator loadAnimator(Resources resources, Theme theme, int id)
+ throws NotFoundException {
XmlResourceParser parser = null;
try {
- parser = context.getResources().getAnimation(id);
- return createAnimatorFromXml(context, parser);
+ parser = resources.getAnimation(id);
+ return createAnimatorFromXml(resources, theme, parser);
} catch (XmlPullParserException ex) {
Resources.NotFoundException rnf =
new Resources.NotFoundException("Can't load animation resource ID #0x" +
@@ -150,7 +169,8 @@
}
if (animator == null) {
- animator = createAnimatorFromXml(context, parser);
+ animator = createAnimatorFromXml(context.getResources(),
+ context.getTheme(), parser);
}
if (animator == null) {
@@ -166,103 +186,8 @@
}
}
- private static Animator createAnimatorFromXml(Context c, XmlPullParser parser)
- throws XmlPullParserException, IOException {
- return createAnimatorFromXml(c, parser, Xml.asAttributeSet(parser), null, 0);
- }
- private static Animator createAnimatorFromXml(Context c, XmlPullParser parser,
- AttributeSet attrs, AnimatorSet parent, int sequenceOrdering)
- throws XmlPullParserException, IOException {
-
- Animator anim = null;
- ArrayList<Animator> childAnims = null;
-
- // Make sure we are on a start tag.
- int type;
- int depth = parser.getDepth();
-
- while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
- && type != XmlPullParser.END_DOCUMENT) {
-
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
-
- String name = parser.getName();
-
- if (name.equals("objectAnimator")) {
- anim = loadObjectAnimator(c, attrs);
- } else if (name.equals("animator")) {
- anim = loadAnimator(c, attrs, null);
- } else if (name.equals("set")) {
- anim = new AnimatorSet();
- TypedArray a = c.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.AnimatorSet);
- int ordering = a.getInt(com.android.internal.R.styleable.AnimatorSet_ordering,
- TOGETHER);
- createAnimatorFromXml(c, parser, attrs, (AnimatorSet) anim, ordering);
- a.recycle();
- } else {
- throw new RuntimeException("Unknown animator name: " + parser.getName());
- }
-
- if (parent != null) {
- if (childAnims == null) {
- childAnims = new ArrayList<Animator>();
- }
- childAnims.add(anim);
- }
- }
- if (parent != null && childAnims != null) {
- Animator[] animsArray = new Animator[childAnims.size()];
- int index = 0;
- for (Animator a : childAnims) {
- animsArray[index++] = a;
- }
- if (sequenceOrdering == TOGETHER) {
- parent.playTogether(animsArray);
- } else {
- parent.playSequentially(animsArray);
- }
- }
-
- return anim;
-
- }
-
- private static ObjectAnimator loadObjectAnimator(Context context, AttributeSet attrs)
- throws NotFoundException {
-
- ObjectAnimator anim = new ObjectAnimator();
-
- loadAnimator(context, attrs, anim);
-
- TypedArray a =
- context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.PropertyAnimator);
-
- String propertyName = a.getString(com.android.internal.R.styleable.PropertyAnimator_propertyName);
-
- anim.setPropertyName(propertyName);
-
- a.recycle();
-
- return anim;
- }
-
- /**
- * Creates a new animation whose parameters come from the specified context and
- * attributes set.
- *
- * @param context the application environment
- * @param attrs the set of attributes holding the animation parameters
- */
- private static ValueAnimator loadAnimator(Context context, AttributeSet attrs, ValueAnimator anim)
- throws NotFoundException {
-
- TypedArray a =
- context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animator);
-
+ private static void parseAnimatorFromTypeArray(ValueAnimator anim, TypedArray a) {
long duration = a.getInt(com.android.internal.R.styleable.Animator_duration, 300);
long startDelay = a.getInt(com.android.internal.R.styleable.Animator_startOffset, 0);
@@ -378,11 +303,123 @@
if (evaluator != null) {
anim.setEvaluator(evaluator);
}
+ }
+
+ private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0);
+ }
+
+ private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser,
+ AttributeSet attrs, AnimatorSet parent, int sequenceOrdering)
+ throws XmlPullParserException, IOException {
+
+ Animator anim = null;
+ ArrayList<Animator> childAnims = null;
+
+ // Make sure we are on a start tag.
+ int type;
+ int depth = parser.getDepth();
+
+ while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+ && type != XmlPullParser.END_DOCUMENT) {
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ String name = parser.getName();
+
+ if (name.equals("objectAnimator")) {
+ anim = loadObjectAnimator(res, theme, attrs);
+ } else if (name.equals("animator")) {
+ anim = loadAnimator(res, theme, attrs, null);
+ } else if (name.equals("set")) {
+ anim = new AnimatorSet();
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AnimatorSet, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, com.android.internal.R.styleable.AnimatorSet);
+ }
+ int ordering = a.getInt(com.android.internal.R.styleable.AnimatorSet_ordering,
+ TOGETHER);
+ createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering);
+ a.recycle();
+ } else {
+ throw new RuntimeException("Unknown animator name: " + parser.getName());
+ }
+
+ if (parent != null) {
+ if (childAnims == null) {
+ childAnims = new ArrayList<Animator>();
+ }
+ childAnims.add(anim);
+ }
+ }
+ if (parent != null && childAnims != null) {
+ Animator[] animsArray = new Animator[childAnims.size()];
+ int index = 0;
+ for (Animator a : childAnims) {
+ animsArray[index++] = a;
+ }
+ if (sequenceOrdering == TOGETHER) {
+ parent.playTogether(animsArray);
+ } else {
+ parent.playSequentially(animsArray);
+ }
+ }
+
+ return anim;
+
+ }
+
+ private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs)
+ throws NotFoundException {
+ ObjectAnimator anim = new ObjectAnimator();
+
+ loadAnimator(res, theme, attrs, anim);
+
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.PropertyAnimator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, R.styleable.PropertyAnimator);
+ }
+
+ String propertyName = a.getString(R.styleable.PropertyAnimator_propertyName);
+
+ anim.setPropertyName(propertyName);
+
+ a.recycle();
+
+ return anim;
+ }
+
+ /**
+ * Creates a new animation whose parameters come from the specified context
+ * and attributes set.
+ *
+ * @param res The resources
+ * @param attrs The set of attributes holding the animation parameters
+ */
+ private static ValueAnimator loadAnimator(Resources res, Theme theme,
+ AttributeSet attrs, ValueAnimator anim)
+ throws NotFoundException {
+
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.Animator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, R.styleable.Animator);
+ }
+
+ parseAnimatorFromTypeArray(anim, a);
final int resID =
a.getResourceId(com.android.internal.R.styleable.Animator_interpolator, 0);
if (resID > 0) {
- anim.setInterpolator(AnimationUtils.loadInterpolator(context, resID));
+ anim.setInterpolator(AnimationUtils.loadInterpolator(res, theme, resID));
}
a.recycle();
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 130754e..8947550 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -16,11 +16,14 @@
package android.animation;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.Log;
import android.util.Property;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
/**
@@ -41,10 +44,15 @@
*
*/
public final class ObjectAnimator extends ValueAnimator {
+ private static final String LOG_TAG = "ObjectAnimator";
+
private static final boolean DBG = false;
- // The target object on which the property exists, set in the constructor
- private Object mTarget;
+ /**
+ * A weak reference to the target object on which the property exists, set
+ * in the constructor. We'll cancel the animation if this goes away.
+ */
+ private WeakReference<Object> mTarget;
private String mPropertyName;
@@ -78,7 +86,7 @@
*
* @param propertyName The name of the property being animated. Should not be null.
*/
- public void setPropertyName(String propertyName) {
+ public void setPropertyName(@NonNull String propertyName) {
// mValues could be null if this is being constructed piecemeal. Just record the
// propertyName to be used later when setValues() is called if so.
if (mValues != null) {
@@ -100,7 +108,7 @@
*
* @param property The property being animated. Should not be null.
*/
- public void setProperty(Property property) {
+ public void setProperty(@NonNull Property property) {
// mValues could be null if this is being constructed piecemeal. Just record the
// propertyName to be used later when setValues() is called if so.
if (mValues != null) {
@@ -134,6 +142,7 @@
* object (if there was just one) or a comma-separated list of all of the
* names (if there are more than one).</p>
*/
+ @Nullable
public String getPropertyName() {
String propertyName = null;
if (mPropertyName != null) {
@@ -176,7 +185,7 @@
* @param propertyName The name of the property being animated.
*/
private ObjectAnimator(Object target, String propertyName) {
- mTarget = target;
+ setTarget(target);
setPropertyName(propertyName);
}
@@ -187,7 +196,7 @@
* @param property The property being animated.
*/
private <T> ObjectAnimator(T target, Property<T, ?> property) {
- mTarget = target;
+ setTarget(target);
setProperty(property);
}
@@ -574,8 +583,9 @@
* @param path The <code>Path</code> to animate values along.
* @return An ObjectAnimator object that is set up to animate along <code>path</code>.
*/
+ @NonNull
public static ObjectAnimator ofObject(Object target, String propertyName,
- TypeConverter<PointF, ?> converter, Path path) {
+ @Nullable TypeConverter<PointF, ?> converter, Path path) {
PropertyValuesHolder pvh = PropertyValuesHolder.ofObject(propertyName, converter, path);
return ofPropertyValuesHolder(target, pvh);
}
@@ -595,6 +605,7 @@
* @param values A set of values that the animation will animate between over time.
* @return An ObjectAnimator object that is set up to animate between the given values.
*/
+ @NonNull
public static <T, V> ObjectAnimator ofObject(T target, Property<T, V> property,
TypeEvaluator<V> evaluator, V... values) {
ObjectAnimator anim = new ObjectAnimator(target, property);
@@ -622,6 +633,7 @@
* @param values A set of values that the animation will animate between over time.
* @return An ObjectAnimator object that is set up to animate between the given values.
*/
+ @NonNull
public static <T, V, P> ObjectAnimator ofObject(T target, Property<T, P> property,
TypeConverter<V, P> converter, TypeEvaluator<V> evaluator, V... values) {
PropertyValuesHolder pvh = PropertyValuesHolder.ofObject(property, converter, evaluator,
@@ -644,8 +656,9 @@
* @param path The <code>Path</code> to animate values along.
* @return An ObjectAnimator object that is set up to animate along <code>path</code>.
*/
- public static <T, V> ObjectAnimator ofObject(T target, Property<T, V> property,
- TypeConverter<PointF, V> converter, Path path) {
+ @NonNull
+ public static <T, V> ObjectAnimator ofObject(T target, @NonNull Property<T, V> property,
+ @Nullable TypeConverter<PointF, V> converter, Path path) {
PropertyValuesHolder pvh = PropertyValuesHolder.ofObject(property, converter, path);
return ofPropertyValuesHolder(target, pvh);
}
@@ -667,10 +680,11 @@
* over time.
* @return An ObjectAnimator object that is set up to animate between the given values.
*/
+ @NonNull
public static ObjectAnimator ofPropertyValuesHolder(Object target,
PropertyValuesHolder... values) {
ObjectAnimator anim = new ObjectAnimator();
- anim.mTarget = target;
+ anim.setTarget(target);
anim.setValues(values);
return anim;
}
@@ -736,10 +750,10 @@
mAutoCancel = cancel;
}
- private boolean hasSameTargetAndProperties(Animator anim) {
+ private boolean hasSameTargetAndProperties(@Nullable Animator anim) {
if (anim instanceof ObjectAnimator) {
PropertyValuesHolder[] theirValues = ((ObjectAnimator) anim).getValues();
- if (((ObjectAnimator) anim).getTarget() == mTarget &&
+ if (((ObjectAnimator) anim).getTarget() == getTarget() &&
mValues.length == theirValues.length) {
for (int i = 0; i < mValues.length; ++i) {
PropertyValuesHolder pvhMine = mValues[i];
@@ -789,11 +803,11 @@
}
}
if (DBG) {
- Log.d("ObjectAnimator", "Anim target, duration: " + mTarget + ", " + getDuration());
+ Log.d(LOG_TAG, "Anim target, duration: " + getTarget() + ", " + getDuration());
for (int i = 0; i < mValues.length; ++i) {
PropertyValuesHolder pvh = mValues[i];
ArrayList<Keyframe> keyframes = pvh.mKeyframeSet.mKeyframes;
- Log.d("ObjectAnimator", " Values[" + i + "]: " +
+ Log.d(LOG_TAG, " Values[" + i + "]: " +
pvh.getPropertyName() + ", " + keyframes.get(0).getValue() + ", " +
keyframes.get(pvh.mKeyframeSet.mNumKeyframes - 1).getValue());
}
@@ -818,9 +832,12 @@
if (!mInitialized) {
// mValueType may change due to setter/getter setup; do this before calling super.init(),
// which uses mValueType to set up the default type evaluator.
- int numValues = mValues.length;
- for (int i = 0; i < numValues; ++i) {
- mValues[i].setupSetterAndGetter(mTarget);
+ final Object target = getTarget();
+ if (target != null) {
+ final int numValues = mValues.length;
+ for (int i = 0; i < numValues; ++i) {
+ mValues[i].setupSetterAndGetter(target);
+ }
}
super.initAnimation();
}
@@ -836,6 +853,7 @@
* <code>ObjectAnimator.ofInt(target, propertyName, 0, 10).setDuration(500).start()</code>.
*/
@Override
+ @NonNull
public ObjectAnimator setDuration(long duration) {
super.setDuration(duration);
return this;
@@ -847,8 +865,9 @@
*
* @return The object being animated
*/
+ @Nullable
public Object getTarget() {
- return mTarget;
+ return mTarget == null ? null : mTarget.get();
}
/**
@@ -857,10 +876,10 @@
* @param target The object being animated
*/
@Override
- public void setTarget(Object target) {
- if (mTarget != target) {
- final Object oldTarget = mTarget;
- mTarget = target;
+ public void setTarget(@Nullable Object target) {
+ final Object oldTarget = getTarget();
+ if (oldTarget != target) {
+ mTarget = target == null ? null : new WeakReference<Object>(target);
if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) {
return;
}
@@ -872,18 +891,26 @@
@Override
public void setupStartValues() {
initAnimation();
- int numValues = mValues.length;
- for (int i = 0; i < numValues; ++i) {
- mValues[i].setupStartValue(mTarget);
+
+ final Object target = getTarget();
+ if (target != null) {
+ final int numValues = mValues.length;
+ for (int i = 0; i < numValues; ++i) {
+ mValues[i].setupStartValue(target);
+ }
}
}
@Override
public void setupEndValues() {
initAnimation();
- int numValues = mValues.length;
- for (int i = 0; i < numValues; ++i) {
- mValues[i].setupEndValue(mTarget);
+
+ final Object target = getTarget();
+ if (target != null) {
+ final int numValues = mValues.length;
+ for (int i = 0; i < numValues; ++i) {
+ mValues[i].setupEndValue(target);
+ }
}
}
@@ -901,10 +928,17 @@
*/
@Override
void animateValue(float fraction) {
+ final Object target = getTarget();
+ if (mTarget != null && target == null) {
+ // We lost the target reference, cancel and clean up.
+ cancel();
+ return;
+ }
+
super.animateValue(fraction);
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
- mValues[i].setAnimatedValue(mTarget);
+ mValues[i].setAnimatedValue(target);
}
}
@@ -915,9 +949,10 @@
}
@Override
+ @NonNull
public String toString() {
String returnVal = "ObjectAnimator@" + Integer.toHexString(hashCode()) + ", target " +
- mTarget;
+ getTarget();
if (mValues != null) {
for (int i = 0; i < mValues.length; ++i) {
returnVal += "\n " + mValues[i].toString();
diff --git a/core/java/android/annotation/PrivateApi.java b/core/java/android/annotation/PrivateApi.java
deleted file mode 100644
index 985eafe..0000000
--- a/core/java/android/annotation/PrivateApi.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.annotation;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Indicates an API is exposed for use by bundled applications.
- * <p>
- * These APIs are not guaranteed to remain consistent release-to-release,
- * and are not for use by apps linking against the SDK.
- * @hide
- */
-@Retention(RetentionPolicy.SOURCE)
-public @interface PrivateApi {
-}
diff --git a/core/java/android/annotation/SystemApi.java b/core/java/android/annotation/SystemApi.java
new file mode 100644
index 0000000..55028eb
--- /dev/null
+++ b/core/java/android/annotation/SystemApi.java
@@ -0,0 +1,44 @@
+/*
+ * 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.annotation;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates an API is exposed for use by bundled system applications.
+ * <p>
+ * These APIs are not guaranteed to remain consistent release-to-release,
+ * and are not for use by apps linking against the Android SDK.
+ * </p><p>
+ * This annotation should only appear on API that is already marked <pre>@hide</pre>.
+ * </p>
+ *
+ * @hide
+ */
+@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE})
+@Retention(RetentionPolicy.SOURCE)
+public @interface SystemApi {
+}
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index d4c4318..628875f 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -68,7 +68,7 @@
* select items accessible directly from the action bar as "action items". You can also
* modify various characteristics of the action bar or remove it completely.</p>
*
- * <p>When using the Quantum themes (default in API 21 or newer) the navigation button
+ * <p>When using the Material themes (default in API 21 or newer) the navigation button
* (formerly "Home") takes over the space previously occupied by the application icon.
* Apps wishing to express a stronger branding should use their brand colors heavily
* in the action bar and other application chrome or use a {@link #setLogo(int) logo}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 23b5f29..f6883e2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5326,7 +5326,8 @@
*
* @hide
*/
- void convertToTranslucent(TranslucentConversionListener callback, ActivityOptions options) {
+ public void convertToTranslucent(TranslucentConversionListener callback,
+ ActivityOptions options) {
boolean drawComplete;
try {
mTranslucentCallback = callback;
@@ -5615,6 +5616,34 @@
mExitTransitionListener = listener;
}
+ /**
+ * Postpone the entering activity transition when Activity was started with
+ * {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity,
+ * android.util.Pair[])}.
+ * <p>This method gives the Activity the ability to delay starting the entering and
+ * shared element transitions until all data is loaded. Until then, the Activity won't
+ * draw into its window, leaving the window transparent. This may also cause the
+ * returning animation to be delayed until data is ready. This method should be
+ * called in {@link #onCreate(android.os.Bundle)} or in
+ * {@link #onActivityReenter(int, android.content.Intent)}.
+ * {@link #startPostponedEnterTransition()} must be called to allow the Activity to
+ * start the transitions. If the Activity did not use
+ * {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity,
+ * android.util.Pair[])}, then this method does nothing.</p>
+ */
+ public void postponeEnterTransition() {
+ mActivityTransitionState.postponeEnterTransition();
+ }
+
+ /**
+ * Begin postponed transitions after {@link #postponeEnterTransition()} was called.
+ * If postponeEnterTransition() was called, you must call startPostponedEnterTransition()
+ * to have your Activity start drawing.
+ */
+ public void startPostponedEnterTransition() {
+ mActivityTransitionState.startPostponedEnterTransition();
+ }
+
// ------------------ Internal API ------------------
final void setParent(Activity parent) {
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index a057c3e..9160452 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -394,8 +394,18 @@
if (sharedElements != null) {
for (int i = 0; i < sharedElements.length; i++) {
Pair<View, String> sharedElement = sharedElements[i];
- names.add(sharedElement.second);
- mappedNames.add(sharedElement.first.getViewName());
+ String sharedElementName = sharedElement.second;
+ if (sharedElementName == null) {
+ throw new IllegalArgumentException("Shared element name must not be null");
+ }
+ String viewName = sharedElement.first.getViewName();
+ if (viewName == null) {
+ throw new IllegalArgumentException("Shared elements must have non-null " +
+ "viewNames");
+ }
+
+ names.add(sharedElementName);
+ mappedNames.add(viewName);
}
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d9adba3..ea46044 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -98,6 +98,7 @@
import com.android.internal.os.SamplingProfilerIntegration;
import com.android.internal.util.FastPrintWriter;
import com.android.org.conscrypt.OpenSSLSocketImpl;
+import com.android.org.conscrypt.TrustedCertificateStore;
import com.google.android.collect.Lists;
import dalvik.system.VMRuntime;
@@ -5049,6 +5050,10 @@
Security.addProvider(new AndroidKeyStoreProvider());
+ // Make sure TrustedCertificateStore looks in the right place for CA certificates
+ final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
+ TrustedCertificateStore.setDefaultUserDirectory(configDir);
+
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index b658597..c7030b0 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -129,9 +129,6 @@
protected static final String KEY_SCALE_TYPE = "shared_element:scaleType";
protected static final String KEY_IMAGE_MATRIX = "shared_element:imageMatrix";
- // The background fade in/out duration. TODO: Enable tuning this.
- public static final int FADE_BACKGROUND_DURATION_MS = 300;
-
protected static final ImageView.ScaleType[] SCALE_TYPE_VALUES = ImageView.ScaleType.values();
/**
@@ -209,16 +206,29 @@
protected ResultReceiver mResultReceiver;
final private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback();
final protected boolean mIsReturning;
+ private Runnable mPendingTransition;
+ private boolean mIsStartingTransition;
+
public ActivityTransitionCoordinator(Window window,
ArrayList<String> allSharedElementNames,
ArrayList<String> accepted, ArrayList<String> localNames,
SharedElementListener listener, boolean isReturning) {
+ this(window, allSharedElementNames, listener, isReturning);
+ viewsReady(accepted, localNames);
+ }
+
+ public ActivityTransitionCoordinator(Window window,
+ ArrayList<String> allSharedElementNames,
+ SharedElementListener listener, boolean isReturning) {
super(new Handler());
mWindow = window;
mListener = listener;
mAllSharedElementNames = allSharedElementNames;
mIsReturning = isReturning;
+ }
+
+ protected void viewsReady(ArrayList<String> accepted, ArrayList<String> localNames) {
setSharedElements(accepted, localNames);
if (getViewsTransition() != null) {
getDecor().captureTransitioningViews(mTransitioningViews);
@@ -251,13 +261,8 @@
if (view == null) {
mEpicenterCallback.setEpicenter(null);
} else {
- int[] loc = new int[2];
- view.getLocationOnScreen(loc);
- int left = loc[0] + Math.round(view.getTranslationX());
- int top = loc[1] + Math.round(view.getTranslationY());
- int right = left + view.getWidth();
- int bottom = top + view.getHeight();
- Rect epicenter = new Rect(left, top, right, bottom);
+ Rect epicenter = new Rect();
+ view.getBoundsOnScreen(epicenter);
mEpicenterCallback.setEpicenter(epicenter);
}
}
@@ -274,6 +279,8 @@
return names;
}
+ public ArrayList<String> getAllSharedElementNames() { return mAllSharedElementNames; }
+
public static void setViewVisibility(Collection<View> views, int visibility) {
if (views != null) {
for (View view : views) {
@@ -286,13 +293,17 @@
if (transition == null || views == null || views.isEmpty()) {
return null;
}
+ // Add the targets to a set containing transition so that transition
+ // remains unaffected. We don't want to modify the targets of transition itself.
TransitionSet set = new TransitionSet();
- set.addTransition(transition);
if (views != null) {
- for (View view: views) {
+ for (View view : views) {
set.addTarget(view);
}
}
+ // By adding the transition after addTarget, we prevent addTarget from
+ // affecting transition.
+ set.addTransition(transition);
return set;
}
@@ -340,6 +351,10 @@
String name = mAllSharedElementNames.get(i);
View sharedElement = sharedElements.get(name);
if (sharedElement != null) {
+ if (sharedElement.getViewName() == null) {
+ throw new IllegalArgumentException("Shared elements must have " +
+ "non-null viewNames");
+ }
mSharedElementNames.add(name);
mSharedElements.add(sharedElement);
}
@@ -492,15 +507,19 @@
protected Bundle captureSharedElementState() {
Bundle bundle = new Bundle();
- int[] tempLoc = new int[2];
+ Rect tempBounds = new Rect();
for (int i = 0; i < mSharedElementNames.size(); i++) {
View sharedElement = mSharedElements.get(i);
String name = mSharedElementNames.get(i);
- captureSharedElementState(sharedElement, name, bundle, tempLoc);
+ captureSharedElementState(sharedElement, name, bundle, tempBounds);
}
return bundle;
}
+ protected long getFadeDuration() {
+ return getWindow().getTransitionBackgroundFadeDuration();
+ }
+
/**
* Captures placement information for Views with a shared element name for
* Activity Transitions.
@@ -509,20 +528,19 @@
* @param name The shared element name in the target Activity to apply the placement
* information for.
* @param transitionArgs Bundle to store shared element placement information.
- * @param tempLoc A temporary int[2] for capturing the current location of views.
+ * @param tempBounds A temporary Rect for capturing the current location of views.
*/
- private static void captureSharedElementState(View view, String name, Bundle transitionArgs,
- int[] tempLoc) {
+ protected static void captureSharedElementState(View view, String name, Bundle transitionArgs,
+ Rect tempBounds) {
Bundle sharedElementBundle = new Bundle();
- view.getLocationOnScreen(tempLoc);
- float scaleX = view.getScaleX();
- sharedElementBundle.putInt(KEY_SCREEN_X, tempLoc[0]);
- int width = Math.round(view.getWidth() * scaleX);
+ tempBounds.set(0, 0, view.getWidth(), view.getHeight());
+ view.getBoundsOnScreen(tempBounds);
+ sharedElementBundle.putInt(KEY_SCREEN_X, tempBounds.left);
+ int width = tempBounds.width();
sharedElementBundle.putInt(KEY_WIDTH, width);
- float scaleY = view.getScaleY();
- sharedElementBundle.putInt(KEY_SCREEN_Y, tempLoc[1]);
- int height = Math.round(view.getHeight() * scaleY);
+ sharedElementBundle.putInt(KEY_SCREEN_Y, tempBounds.top);
+ int height = tempBounds.height();
sharedElementBundle.putInt(KEY_HEIGHT, height);
sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ());
@@ -548,6 +566,32 @@
transitionArgs.putBundle(name, sharedElementBundle);
}
+
+ protected void startTransition(Runnable runnable) {
+ if (mIsStartingTransition) {
+ mPendingTransition = runnable;
+ } else {
+ mIsStartingTransition = true;
+ runnable.run();
+ }
+ }
+
+ protected void transitionStarted() {
+ mIsStartingTransition = false;
+ }
+
+ protected class ContinueTransitionListener extends Transition.TransitionListenerAdapter {
+ @Override
+ public void onTransitionStart(Transition transition) {
+ mIsStartingTransition = false;
+ Runnable pending = mPendingTransition;
+ mPendingTransition = null;
+ if (pending != null) {
+ startTransition(pending);
+ }
+ }
+ }
+
private static int scaleTypeToInt(ImageView.ScaleType scaleType) {
for (int i = 0; i < SCALE_TYPE_VALUES.length; i++) {
if (scaleType == SCALE_TYPE_VALUES[i]) {
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index b32e9ad..d94dadd 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -87,6 +87,11 @@
*/
private boolean mHasExited;
+ /**
+ * Postpone painting and starting the enter transition until this is false.
+ */
+ private boolean mIsEnterPostponed;
+
public ActivityTransitionState() {
}
@@ -140,15 +145,38 @@
if (mEnterActivityOptions.isReturning()) {
restoreExitedViews();
activity.getWindow().getDecorView().setVisibility(View.VISIBLE);
- mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
- resultReceiver, sharedElementNames, mExitingFrom, mExitingTo);
+ }
+ mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
+ resultReceiver, sharedElementNames, mEnterActivityOptions.isReturning());
+
+ if (!mIsEnterPostponed) {
+ startEnter();
+ }
+ }
+
+ public void postponeEnterTransition() {
+ mIsEnterPostponed = true;
+ }
+
+ public void startPostponedEnterTransition() {
+ if (mIsEnterPostponed) {
+ mIsEnterPostponed = false;
+ if (mEnterTransitionCoordinator != null) {
+ startEnter();
+ }
+ }
+ }
+
+ private void startEnter() {
+ if (mEnterActivityOptions.isReturning()) {
+ mEnterTransitionCoordinator.viewsReady(mExitingFrom, mExitingTo);
} else {
- mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
- resultReceiver, sharedElementNames, null, null);
- mEnteringNames = sharedElementNames;
+ mEnterTransitionCoordinator.viewsReady(null, null);
+ mEnteringNames = mEnterTransitionCoordinator.getAllSharedElementNames();
mEnteringFrom = mEnterTransitionCoordinator.getAcceptedNames();
mEnteringTo = mEnterTransitionCoordinator.getMappedNames();
}
+
mExitingFrom = null;
mExitingTo = null;
mEnterActivityOptions = null;
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index c29d75e..94ea2c5 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -354,9 +354,11 @@
private static class ActivityContainerWrapper {
private final IActivityContainer mIActivityContainer;
private final CloseGuard mGuard = CloseGuard.get();
+ boolean mOpened; // Protected by mGuard.
ActivityContainerWrapper(IActivityContainer container) {
mIActivityContainer = container;
+ mOpened = true;
mGuard.open("release");
}
@@ -424,11 +426,16 @@
}
void release() {
- if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called");
- try {
- mIActivityContainer.release();
- mGuard.close();
- } catch (RemoteException e) {
+ synchronized (mGuard) {
+ if (mOpened) {
+ if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called");
+ try {
+ mIActivityContainer.release();
+ mGuard.close();
+ } catch (RemoteException e) {
+ }
+ mOpened = false;
+ }
}
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 5867232..a480219 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -189,7 +189,9 @@
/** @hide Retrieve current usage stats via {@link UsageStatsManager}. */
public static final int OP_GET_USAGE_STATS = 43;
/** @hide */
- public static final int _NUM_OP = 44;
+ public static final int OP_MUTE_MICROPHONE = 44;
+ /** @hide */
+ public static final int _NUM_OP = 45;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION =
@@ -257,6 +259,7 @@
OP_COARSE_LOCATION,
OP_COARSE_LOCATION,
OP_GET_USAGE_STATS,
+ OP_MUTE_MICROPHONE
};
/**
@@ -308,6 +311,7 @@
OPSTR_MONITOR_LOCATION,
OPSTR_MONITOR_HIGH_POWER_LOCATION,
null,
+ null,
};
/**
@@ -358,7 +362,8 @@
"WAKE_LOCK",
"MONITOR_LOCATION",
"MONITOR_HIGH_POWER_LOCATION",
- "GET_USAGE_STATS"
+ "GET_USAGE_STATS",
+ "OP_MUTE_MICROPHONE",
};
/**
@@ -410,6 +415,7 @@
null, // no permission for generic location monitoring
null, // no permission for high power location monitoring
android.Manifest.permission.PACKAGE_USAGE_STATS,
+ null, // no permission for muting/unmuting microphone
};
/**
@@ -462,6 +468,7 @@
null, //MONITOR_LOCATION
null, //MONITOR_HIGH_POWER_LOCATION
null, //GET_USAGE_STATS
+ UserManager.DISALLOW_UNMUTE_MICROPHONE, // MUTE_MICROPHONE
};
/**
@@ -512,6 +519,7 @@
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_IGNORED, // OP_GET_USAGE_STATS
+ AppOpsManager.MODE_ALLOWED,
};
/**
@@ -566,6 +574,7 @@
false,
false,
false,
+ false,
};
private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 89ee145..01a388f 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -16,36 +16,53 @@
package android.app;
+import com.android.internal.util.FastPrintWriter;
+
+import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.LogWriter;
-import com.android.internal.util.FastPrintWriter;
+import android.util.Pair;
+import android.view.View;
+import android.view.ViewGroup;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collection;
final class BackStackState implements Parcelable {
final int[] mOps;
final int mTransition;
final int mTransitionStyle;
+ final int mCustomTransition;
+ final int mSceneRoot;
final String mName;
final int mIndex;
final int mBreadCrumbTitleRes;
final CharSequence mBreadCrumbTitleText;
final int mBreadCrumbShortTitleRes;
final CharSequence mBreadCrumbShortTitleText;
+ final ArrayList<String> mSharedElementSourceNames;
+ final ArrayList<String> mSharedElementTargetNames;
public BackStackState(FragmentManagerImpl fm, BackStackRecord bse) {
int numRemoved = 0;
BackStackRecord.Op op = bse.mHead;
while (op != null) {
- if (op.removed != null) numRemoved += op.removed.size();
+ if (op.removed != null) {
+ numRemoved += op.removed.size();
+ }
op = op.next;
}
- mOps = new int[bse.mNumOp*7 + numRemoved];
+ mOps = new int[bse.mNumOp * 7 + numRemoved];
if (!bse.mAddToBackStack) {
throw new IllegalStateException("Not on back stack");
@@ -63,7 +80,7 @@
if (op.removed != null) {
final int N = op.removed.size();
mOps[pos++] = N;
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
mOps[pos++] = op.removed.get(i).mIndex;
}
} else {
@@ -79,6 +96,10 @@
mBreadCrumbTitleText = bse.mBreadCrumbTitleText;
mBreadCrumbShortTitleRes = bse.mBreadCrumbShortTitleRes;
mBreadCrumbShortTitleText = bse.mBreadCrumbShortTitleText;
+ mCustomTransition = bse.mCustomTransition;
+ mSceneRoot = bse.mSceneRoot;
+ mSharedElementSourceNames = bse.mSharedElementSourceNames;
+ mSharedElementTargetNames = bse.mSharedElementTargetNames;
}
public BackStackState(Parcel in) {
@@ -91,6 +112,10 @@
mBreadCrumbTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mBreadCrumbShortTitleRes = in.readInt();
mBreadCrumbShortTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ mCustomTransition = in.readInt();
+ mSceneRoot = in.readInt();
+ mSharedElementSourceNames = in.createStringArrayList();
+ mSharedElementTargetNames = in.createStringArrayList();
}
public BackStackRecord instantiate(FragmentManagerImpl fm) {
@@ -100,8 +125,10 @@
while (pos < mOps.length) {
BackStackRecord.Op op = new BackStackRecord.Op();
op.cmd = mOps[pos++];
- if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
- "Instantiate " + bse + " op #" + num + " base fragment #" + mOps[pos]);
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(FragmentManagerImpl.TAG,
+ "Instantiate " + bse + " op #" + num + " base fragment #" + mOps[pos]);
+ }
int findex = mOps[pos++];
if (findex >= 0) {
Fragment f = fm.mActive.get(findex);
@@ -116,9 +143,11 @@
final int N = mOps[pos++];
if (N > 0) {
op.removed = new ArrayList<Fragment>(N);
- for (int i=0; i<N; i++) {
- if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
- "Instantiate " + bse + " set remove fragment #" + mOps[pos]);
+ for (int i = 0; i < N; i++) {
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(FragmentManagerImpl.TAG,
+ "Instantiate " + bse + " set remove fragment #" + mOps[pos]);
+ }
Fragment r = fm.mActive.get(mOps[pos++]);
op.removed.add(r);
}
@@ -135,6 +164,10 @@
bse.mBreadCrumbTitleText = mBreadCrumbTitleText;
bse.mBreadCrumbShortTitleRes = mBreadCrumbShortTitleRes;
bse.mBreadCrumbShortTitleText = mBreadCrumbShortTitleText;
+ bse.mCustomTransition = mCustomTransition;
+ bse.mSceneRoot = mSceneRoot;
+ bse.mSharedElementSourceNames = mSharedElementSourceNames;
+ bse.mSharedElementTargetNames = mSharedElementTargetNames;
bse.bumpBackStackNesting(1);
return bse;
}
@@ -153,6 +186,10 @@
TextUtils.writeToParcel(mBreadCrumbTitleText, dest, 0);
dest.writeInt(mBreadCrumbShortTitleRes);
TextUtils.writeToParcel(mBreadCrumbShortTitleText, dest, 0);
+ dest.writeInt(mCustomTransition);
+ dest.writeInt(mSceneRoot);
+ dest.writeStringList(mSharedElementSourceNames);
+ dest.writeStringList(mSharedElementTargetNames);
}
public static final Parcelable.Creator<BackStackState> CREATOR
@@ -217,6 +254,11 @@
int mBreadCrumbShortTitleRes;
CharSequence mBreadCrumbShortTitleText;
+ int mCustomTransition;
+ int mSceneRoot;
+ ArrayList<String> mSharedElementSourceNames;
+ ArrayList<String> mSharedElementTargetNames;
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder(128);
@@ -240,78 +282,112 @@
void dump(String prefix, PrintWriter writer, boolean full) {
if (full) {
- writer.print(prefix); writer.print("mName="); writer.print(mName);
- writer.print(" mIndex="); writer.print(mIndex);
- writer.print(" mCommitted="); writer.println(mCommitted);
+ writer.print(prefix);
+ writer.print("mName=");
+ writer.print(mName);
+ writer.print(" mIndex=");
+ writer.print(mIndex);
+ writer.print(" mCommitted=");
+ writer.println(mCommitted);
if (mTransition != FragmentTransaction.TRANSIT_NONE) {
- writer.print(prefix); writer.print("mTransition=#");
- writer.print(Integer.toHexString(mTransition));
- writer.print(" mTransitionStyle=#");
- writer.println(Integer.toHexString(mTransitionStyle));
+ writer.print(prefix);
+ writer.print("mTransition=#");
+ writer.print(Integer.toHexString(mTransition));
+ writer.print(" mTransitionStyle=#");
+ writer.println(Integer.toHexString(mTransitionStyle));
}
- if (mEnterAnim != 0 || mExitAnim !=0) {
- writer.print(prefix); writer.print("mEnterAnim=#");
- writer.print(Integer.toHexString(mEnterAnim));
- writer.print(" mExitAnim=#");
- writer.println(Integer.toHexString(mExitAnim));
+ if (mEnterAnim != 0 || mExitAnim != 0) {
+ writer.print(prefix);
+ writer.print("mEnterAnim=#");
+ writer.print(Integer.toHexString(mEnterAnim));
+ writer.print(" mExitAnim=#");
+ writer.println(Integer.toHexString(mExitAnim));
}
- if (mPopEnterAnim != 0 || mPopExitAnim !=0) {
- writer.print(prefix); writer.print("mPopEnterAnim=#");
- writer.print(Integer.toHexString(mPopEnterAnim));
- writer.print(" mPopExitAnim=#");
- writer.println(Integer.toHexString(mPopExitAnim));
+ if (mPopEnterAnim != 0 || mPopExitAnim != 0) {
+ writer.print(prefix);
+ writer.print("mPopEnterAnim=#");
+ writer.print(Integer.toHexString(mPopEnterAnim));
+ writer.print(" mPopExitAnim=#");
+ writer.println(Integer.toHexString(mPopExitAnim));
}
if (mBreadCrumbTitleRes != 0 || mBreadCrumbTitleText != null) {
- writer.print(prefix); writer.print("mBreadCrumbTitleRes=#");
- writer.print(Integer.toHexString(mBreadCrumbTitleRes));
- writer.print(" mBreadCrumbTitleText=");
- writer.println(mBreadCrumbTitleText);
+ writer.print(prefix);
+ writer.print("mBreadCrumbTitleRes=#");
+ writer.print(Integer.toHexString(mBreadCrumbTitleRes));
+ writer.print(" mBreadCrumbTitleText=");
+ writer.println(mBreadCrumbTitleText);
}
if (mBreadCrumbShortTitleRes != 0 || mBreadCrumbShortTitleText != null) {
- writer.print(prefix); writer.print("mBreadCrumbShortTitleRes=#");
- writer.print(Integer.toHexString(mBreadCrumbShortTitleRes));
- writer.print(" mBreadCrumbShortTitleText=");
- writer.println(mBreadCrumbShortTitleText);
+ writer.print(prefix);
+ writer.print("mBreadCrumbShortTitleRes=#");
+ writer.print(Integer.toHexString(mBreadCrumbShortTitleRes));
+ writer.print(" mBreadCrumbShortTitleText=");
+ writer.println(mBreadCrumbShortTitleText);
}
}
if (mHead != null) {
- writer.print(prefix); writer.println("Operations:");
+ writer.print(prefix);
+ writer.println("Operations:");
String innerPrefix = prefix + " ";
Op op = mHead;
int num = 0;
while (op != null) {
String cmdStr;
switch (op.cmd) {
- case OP_NULL: cmdStr="NULL"; break;
- case OP_ADD: cmdStr="ADD"; break;
- case OP_REPLACE: cmdStr="REPLACE"; break;
- case OP_REMOVE: cmdStr="REMOVE"; break;
- case OP_HIDE: cmdStr="HIDE"; break;
- case OP_SHOW: cmdStr="SHOW"; break;
- case OP_DETACH: cmdStr="DETACH"; break;
- case OP_ATTACH: cmdStr="ATTACH"; break;
- default: cmdStr="cmd=" + op.cmd; break;
+ case OP_NULL:
+ cmdStr = "NULL";
+ break;
+ case OP_ADD:
+ cmdStr = "ADD";
+ break;
+ case OP_REPLACE:
+ cmdStr = "REPLACE";
+ break;
+ case OP_REMOVE:
+ cmdStr = "REMOVE";
+ break;
+ case OP_HIDE:
+ cmdStr = "HIDE";
+ break;
+ case OP_SHOW:
+ cmdStr = "SHOW";
+ break;
+ case OP_DETACH:
+ cmdStr = "DETACH";
+ break;
+ case OP_ATTACH:
+ cmdStr = "ATTACH";
+ break;
+ default:
+ cmdStr = "cmd=" + op.cmd;
+ break;
}
- writer.print(prefix); writer.print(" Op #"); writer.print(num);
- writer.print(": "); writer.print(cmdStr);
- writer.print(" "); writer.println(op.fragment);
+ writer.print(prefix);
+ writer.print(" Op #");
+ writer.print(num);
+ writer.print(": ");
+ writer.print(cmdStr);
+ writer.print(" ");
+ writer.println(op.fragment);
if (full) {
if (op.enterAnim != 0 || op.exitAnim != 0) {
- writer.print(innerPrefix); writer.print("enterAnim=#");
- writer.print(Integer.toHexString(op.enterAnim));
- writer.print(" exitAnim=#");
- writer.println(Integer.toHexString(op.exitAnim));
+ writer.print(innerPrefix);
+ writer.print("enterAnim=#");
+ writer.print(Integer.toHexString(op.enterAnim));
+ writer.print(" exitAnim=#");
+ writer.println(Integer.toHexString(op.exitAnim));
}
if (op.popEnterAnim != 0 || op.popExitAnim != 0) {
- writer.print(innerPrefix); writer.print("popEnterAnim=#");
- writer.print(Integer.toHexString(op.popEnterAnim));
- writer.print(" popExitAnim=#");
- writer.println(Integer.toHexString(op.popExitAnim));
+ writer.print(innerPrefix);
+ writer.print("popEnterAnim=#");
+ writer.print(Integer.toHexString(op.popEnterAnim));
+ writer.print(" popExitAnim=#");
+ writer.println(Integer.toHexString(op.popExitAnim));
}
}
if (op.removed != null && op.removed.size() > 0) {
- for (int i=0; i<op.removed.size(); i++) {
+ for (int i = 0; i < op.removed.size(); i++) {
writer.print(innerPrefix);
if (op.removed.size() == 1) {
writer.print("Removed: ");
@@ -319,8 +395,10 @@
if (i == 0) {
writer.println("Removed:");
}
- writer.print(innerPrefix); writer.print(" #"); writer.print(i);
- writer.print(": ");
+ writer.print(innerPrefix);
+ writer.print(" #");
+ writer.print(i);
+ writer.print(": ");
}
writer.println(op.removed.get(i));
}
@@ -494,6 +572,51 @@
return this;
}
+ @Override
+ public FragmentTransaction setCustomTransition(int sceneRootId, int transitionId) {
+ mSceneRoot = sceneRootId;
+ mCustomTransition = transitionId;
+ return this;
+ }
+
+ @Override
+ public FragmentTransaction setSharedElement(View sharedElement, String name) {
+ String viewName = sharedElement.getViewName();
+ if (viewName == null) {
+ throw new IllegalArgumentException("Unique viewNames are required for all" +
+ " sharedElements");
+ }
+ mSharedElementSourceNames = new ArrayList<String>(1);
+ mSharedElementSourceNames.add(viewName);
+
+ mSharedElementTargetNames = new ArrayList<String>(1);
+ mSharedElementTargetNames.add(name);
+ return this;
+ }
+
+ @Override
+ public FragmentTransaction setSharedElements(Pair<View, String>... sharedElements) {
+ if (sharedElements == null || sharedElements.length == 0) {
+ mSharedElementSourceNames = null;
+ mSharedElementTargetNames = null;
+ } else {
+ ArrayList<String> sourceNames = new ArrayList<String>(sharedElements.length);
+ ArrayList<String> targetNames = new ArrayList<String>(sharedElements.length);
+ for (int i = 0; i < sharedElements.length; i++) {
+ String viewName = sharedElements[i].first.getViewName();
+ if (viewName == null) {
+ throw new IllegalArgumentException("Unique viewNames are required for all" +
+ " sharedElements");
+ }
+ sourceNames.add(viewName);
+ targetNames.add(sharedElements[i].second);
+ }
+ mSharedElementSourceNames = sourceNames;
+ mSharedElementTargetNames = targetNames;
+ }
+ return this;
+ }
+
public FragmentTransaction setTransitionStyle(int styleRes) {
mTransitionStyle = styleRes;
return this;
@@ -550,21 +673,27 @@
if (!mAddToBackStack) {
return;
}
- if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting in " + this
- + " by " + amt);
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(TAG, "Bump nesting in " + this
+ + " by " + amt);
+ }
Op op = mHead;
while (op != null) {
if (op.fragment != null) {
op.fragment.mBackStackNesting += amt;
- if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
- + op.fragment + " to " + op.fragment.mBackStackNesting);
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(TAG, "Bump nesting of "
+ + op.fragment + " to " + op.fragment.mBackStackNesting);
+ }
}
if (op.removed != null) {
- for (int i=op.removed.size()-1; i>=0; i--) {
+ for (int i = op.removed.size() - 1; i >= 0; i--) {
Fragment r = op.removed.get(i);
r.mBackStackNesting += amt;
- if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
- + r + " to " + r.mBackStackNesting);
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(TAG, "Bump nesting of "
+ + r + " to " + r.mBackStackNesting);
+ }
}
}
op = op.next;
@@ -578,9 +707,11 @@
public int commitAllowingStateLoss() {
return commitInternal(true);
}
-
+
int commitInternal(boolean allowStateLoss) {
- if (mCommitted) throw new IllegalStateException("commit already called");
+ if (mCommitted) {
+ throw new IllegalStateException("commit already called");
+ }
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
@@ -597,9 +728,11 @@
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
-
+
public void run() {
- if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this);
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(TAG, "Run: " + this);
+ }
if (mAddToBackStack) {
if (mIndex < 0) {
@@ -609,6 +742,9 @@
bumpBackStackNesting(1);
+ TransitionState state = beginTransition(mSharedElementSourceNames,
+ mSharedElementTargetNames);
+
Op op = mHead;
while (op != null) {
switch (op.cmd) {
@@ -616,14 +752,17 @@
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
- } break;
+ }
+ break;
case OP_REPLACE: {
Fragment f = op.fragment;
if (mManager.mAdded != null) {
- for (int i=0; i<mManager.mAdded.size(); i++) {
+ for (int i = 0; i < mManager.mAdded.size(); i++) {
Fragment old = mManager.mAdded.get(i);
- if (FragmentManagerImpl.DEBUG) Log.v(TAG,
- "OP_REPLACE: adding=" + f + " old=" + old);
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(TAG,
+ "OP_REPLACE: adding=" + f + " old=" + old);
+ }
if (f == null || old.mContainerId == f.mContainerId) {
if (old == f) {
op.fragment = f = null;
@@ -635,8 +774,10 @@
old.mNextAnim = op.exitAnim;
if (mAddToBackStack) {
old.mBackStackNesting += 1;
- if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
- + old + " to " + old.mBackStackNesting);
+ if (FragmentManagerImpl.DEBUG) {
+ Log.v(TAG, "Bump nesting of "
+ + old + " to " + old.mBackStackNesting);
+ }
}
mManager.removeFragment(old, mTransition, mTransitionStyle);
}
@@ -647,32 +788,38 @@
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
}
- } break;
+ }
+ break;
case OP_REMOVE: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.removeFragment(f, mTransition, mTransitionStyle);
- } break;
+ }
+ break;
case OP_HIDE: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.hideFragment(f, mTransition, mTransitionStyle);
- } break;
+ }
+ break;
case OP_SHOW: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.showFragment(f, mTransition, mTransitionStyle);
- } break;
+ }
+ break;
case OP_DETACH: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.detachFragment(f, mTransition, mTransitionStyle);
- } break;
+ }
+ break;
case OP_ATTACH: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.attachFragment(f, mTransition, mTransitionStyle);
- } break;
+ }
+ break;
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
@@ -687,9 +834,174 @@
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
+
+ if (state != null) {
+ updateTransitionEndState(state, mSharedElementTargetNames);
+ }
}
- public void popFromBackStack(boolean doStateMove) {
+ private TransitionState beginTransition(ArrayList<String> sourceNames,
+ ArrayList<String> targetNames) {
+ if (mCustomTransition <= 0 || mSceneRoot <= 0) {
+ return null;
+ }
+ View rootView = mManager.mContainer.findViewById(mSceneRoot);
+ if (!(rootView instanceof ViewGroup)) {
+ throw new IllegalArgumentException("SceneRoot is not a ViewGroup");
+ }
+ TransitionState state = new TransitionState();
+ // get Transition scene root and create Transitions
+ state.sceneRoot = (ViewGroup) rootView;
+ state.sceneRoot.captureTransitioningViews(state.transitioningViews);
+
+ state.exitTransition = TransitionInflater.from(mManager.mActivity)
+ .inflateTransition(mCustomTransition);
+ state.sharedElementTransition = TransitionInflater.from(mManager.mActivity)
+ .inflateTransition(mCustomTransition);
+ state.enterTransition = TransitionInflater.from(mManager.mActivity)
+ .inflateTransition(mCustomTransition);
+ // Adding a non-existent target view makes sure that the transitions don't target
+ // any views by default. They'll only target the views we tell add. If we don't
+ // add any, then no views will be targeted.
+ View nonExistentView = new View(mManager.mActivity);
+ state.enterTransition.addTarget(nonExistentView);
+ state.exitTransition.addTarget(nonExistentView);
+ state.sharedElementTransition.addTarget(nonExistentView);
+
+ setSharedElementEpicenter(state.enterTransition, state);
+
+ state.excludingTransition = new TransitionSet()
+ .addTransition(state.exitTransition)
+ .addTransition(state.enterTransition);
+
+ if (sourceNames != null) {
+ // Map shared elements.
+ state.sceneRoot.findNamedViews(state.namedViews);
+ state.namedViews.retainAll(sourceNames);
+ View epicenterView = state.namedViews.get(sourceNames.get(0));
+ if (epicenterView != null) {
+ // The epicenter is only the first shared element.
+ setEpicenter(state.exitTransition, epicenterView);
+ setEpicenter(state.sharedElementTransition, epicenterView);
+ }
+ state.transitioningViews.removeAll(state.namedViews.values());
+ state.excludingTransition.addTransition(state.sharedElementTransition);
+ addTransitioningViews(state.sharedElementTransition, state.namedViews.values());
+ }
+
+ // Adds the (maybe) exiting views, not including the shared element.
+ // If some stay, that's ok.
+ addTransitioningViews(state.exitTransition, state.transitioningViews);
+
+ // Prepare for shared element name mapping. This could be chained in the case
+ // of popping several back stack states.
+ state.excludingTransition.setNameOverrides(new ArrayMap<String, String>());
+ setNameOverrides(state, sourceNames, targetNames);
+
+ // Don't include any subtree in the views that are hidden when capturing the
+ // view hierarchy transitions. They should be as if not there.
+ excludeHiddenFragments(state, true);
+
+ TransitionManager.beginDelayedTransition(state.sceneRoot, state.excludingTransition);
+ return state;
+ }
+
+ private void updateTransitionEndState(TransitionState state, ArrayList<String> names) {
+ // Find all views that are entering.
+ ArrayList<View> enteringViews = new ArrayList<View>();
+ state.sceneRoot.captureTransitioningViews(enteringViews);
+ enteringViews.removeAll(state.transitioningViews);
+
+ if (names != null) {
+ // find all shared elements.
+ state.namedViews.clear();
+ state.sceneRoot.findNamedViews(state.namedViews);
+ state.namedViews.retainAll(names);
+ if (!state.namedViews.isEmpty()) {
+ enteringViews.removeAll(state.namedViews.values());
+ addTransitioningViews(state.sharedElementTransition, state.namedViews.values());
+ // now we know the epicenter of the entering transition.
+ state.mEnteringEpicenterView = state.namedViews.get(names.get(0));
+ }
+ }
+
+ // Add all entering views to the enter transition.
+ addTransitioningViews(state.enterTransition, enteringViews);
+
+ // Don't allow capturing state for the newly-hidden fragments.
+ excludeHiddenFragments(state, false);
+
+ // Allow capturing state for the newly-shown fragments
+ includeVisibleFragments(state.excludingTransition);
+ }
+
+ private void addTransitioningViews(Transition transition, Collection<View> views) {
+ if (views.isEmpty()) {
+ // Add a view so that we can modify the valid views at the end of the
+ // fragment transaction.
+ transition.addTarget(new View(mManager.mActivity));
+ } else {
+ for (View view : views) {
+ transition.addTarget(view);
+ }
+ }
+ }
+
+ private void excludeHiddenFragments(TransitionState state, boolean forceExclude) {
+ if (mManager.mAdded != null) {
+ for (int i = 0; i < mManager.mAdded.size(); i++) {
+ Fragment fragment = mManager.mAdded.get(i);
+ if (fragment.mView != null && fragment.mHidden
+ && (forceExclude || !state.hiddenViews.contains(fragment.mView))) {
+ state.excludingTransition.excludeTarget(fragment.mView, true);
+ state.hiddenViews.add(fragment.mView);
+ }
+ }
+ }
+ if (forceExclude && state.hiddenViews.isEmpty()) {
+ state.excludingTransition.excludeTarget(new View(mManager.mActivity), true);
+ }
+ }
+
+ private void includeVisibleFragments(Transition transition) {
+ if (mManager.mAdded != null) {
+ for (int i = 0; i < mManager.mAdded.size(); i++) {
+ Fragment fragment = mManager.mAdded.get(i);
+ if (fragment.mView != null && !fragment.mHidden) {
+ transition.excludeTarget(fragment.mView, false);
+ }
+ }
+ }
+ }
+
+ private static void setEpicenter(Transition transition, View view) {
+ final Rect epicenter = new Rect();
+ view.getBoundsOnScreen(epicenter);
+
+ transition.setEpicenterCallback(new Transition.EpicenterCallback() {
+ @Override
+ public Rect onGetEpicenter(Transition transition) {
+ return epicenter;
+ }
+ });
+ }
+
+ private void setSharedElementEpicenter(Transition transition, final TransitionState state) {
+ transition.setEpicenterCallback(new Transition.EpicenterCallback() {
+ private Rect mEpicenter;
+
+ @Override
+ public Rect onGetEpicenter(Transition transition) {
+ if (mEpicenter == null && state.mEnteringEpicenterView != null) {
+ mEpicenter = new Rect();
+ state.mEnteringEpicenterView.getBoundsOnScreen(mEpicenter);
+ }
+ return mEpicenter;
+ }
+ });
+ }
+
+ public TransitionState popFromBackStack(boolean doStateMove, TransitionState state) {
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "popFromBackStack: " + this);
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
@@ -698,6 +1010,12 @@
pw.flush();
}
+ if (state == null) {
+ state = beginTransition(mSharedElementTargetNames, mSharedElementSourceNames);
+ } else {
+ setNameOverrides(state, mSharedElementTargetNames, mSharedElementSourceNames);
+ }
+
bumpBackStackNesting(-1);
Op op = mTail;
@@ -709,7 +1027,8 @@
mManager.removeFragment(f,
FragmentManagerImpl.reverseTransit(mTransition),
mTransitionStyle);
- } break;
+ }
+ break;
case OP_REPLACE: {
Fragment f = op.fragment;
if (f != null) {
@@ -719,42 +1038,48 @@
mTransitionStyle);
}
if (op.removed != null) {
- for (int i=0; i<op.removed.size(); i++) {
+ for (int i = 0; i < op.removed.size(); i++) {
Fragment old = op.removed.get(i);
old.mNextAnim = op.popEnterAnim;
mManager.addFragment(old, false);
}
}
- } break;
+ }
+ break;
case OP_REMOVE: {
Fragment f = op.fragment;
f.mNextAnim = op.popEnterAnim;
mManager.addFragment(f, false);
- } break;
+ }
+ break;
case OP_HIDE: {
Fragment f = op.fragment;
f.mNextAnim = op.popEnterAnim;
mManager.showFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
- } break;
+ }
+ break;
case OP_SHOW: {
Fragment f = op.fragment;
f.mNextAnim = op.popExitAnim;
mManager.hideFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
- } break;
+ }
+ break;
case OP_DETACH: {
Fragment f = op.fragment;
f.mNextAnim = op.popEnterAnim;
mManager.attachFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
- } break;
+ }
+ break;
case OP_ATTACH: {
Fragment f = op.fragment;
f.mNextAnim = op.popExitAnim;
mManager.detachFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
- } break;
+ }
+ break;
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
@@ -766,12 +1091,39 @@
if (doStateMove) {
mManager.moveToState(mManager.mCurState,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true);
+ if (state != null) {
+ updateTransitionEndState(state, mSharedElementSourceNames);
+ state = null;
+ }
}
if (mIndex >= 0) {
mManager.freeBackStackIndex(mIndex);
mIndex = -1;
}
+ return state;
+ }
+
+ private static void setNameOverride(Transition transition, String source, String target) {
+ ArrayMap<String, String> overrides = transition.getNameOverrides();
+ for (int index = 0; index < overrides.size(); index++) {
+ if (source.equals(overrides.valueAt(index))) {
+ overrides.setValueAt(index, target);
+ return;
+ }
+ }
+ overrides.put(source, target);
+ }
+
+ private static void setNameOverrides(TransitionState state, ArrayList<String> sourceNames,
+ ArrayList<String> targetNames) {
+ if (sourceNames != null) {
+ for (int i = 0; i < sourceNames.size(); i++) {
+ String source = sourceNames.get(i);
+ String target = targetNames.get(i);
+ setNameOverride(state.excludingTransition, source, target);
+ }
+ }
}
public String getName() {
@@ -789,4 +1141,16 @@
public boolean isEmpty() {
return mNumOp == 0;
}
+
+ public class TransitionState {
+ public ArrayList<View> hiddenViews = new ArrayList<View>();
+ public ArrayList<View> transitioningViews = new ArrayList<View>();
+ public ArrayMap<String, View> namedViews = new ArrayMap<String, View>();
+ public Transition exitTransition;
+ public Transition sharedElementTransition;
+ public Transition enterTransition;
+ public TransitionSet excludingTransition;
+ public ViewGroup sceneRoot;
+ public View mEnteringEpicenterView;
+ }
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index e03224c..a42bd3b 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -59,9 +59,7 @@
import android.hardware.ISerialManager;
import android.hardware.SerialManager;
import android.hardware.SystemSensorManager;
-import android.hardware.hdmi.HdmiCecManager;
import android.hardware.hdmi.HdmiControlManager;
-import android.hardware.hdmi.IHdmiCecService;
import android.hardware.hdmi.IHdmiControlService;
import android.hardware.camera2.CameraManager;
import android.hardware.display.DisplayManager;
@@ -117,9 +115,9 @@
import android.os.storage.StorageManager;
import android.print.IPrintManager;
import android.print.PrintManager;
+import android.service.fingerprint.IFingerprintService;
import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.FingerprintManagerReceiver;
-import android.service.fingerprint.FingerprintService;
+import android.telecomm.TelecommManager;
import android.telephony.TelephonyManager;
import android.content.ClipboardManager;
import android.util.AndroidRuntimeException;
@@ -137,13 +135,14 @@
import android.accounts.AccountManager;
import android.accounts.IAccountManager;
import android.app.admin.DevicePolicyManager;
-import android.app.task.ITaskManager;
+import android.app.job.IJobScheduler;
import android.app.trust.TrustManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsService;
import com.android.internal.appwidget.IAppWidgetService.Stub;
import com.android.internal.os.IDropBoxManagerService;
+import com.android.internal.telecomm.ITelecommService;
import java.io.File;
import java.io.FileInputStream;
@@ -386,12 +385,6 @@
return new BluetoothManager(ctx);
}});
- registerService(HDMI_CEC_SERVICE, new StaticServiceFetcher() {
- public Object createStaticService() {
- IBinder b = ServiceManager.getService(HDMI_CEC_SERVICE);
- return new HdmiCecManager(IHdmiCecService.Stub.asInterface(b));
- }});
-
registerService(HDMI_CONTROL_SERVICE, new StaticServiceFetcher() {
public Object createStaticService() {
IBinder b = ServiceManager.getService(HDMI_CONTROL_SERVICE);
@@ -472,11 +465,6 @@
return new KeyguardManager();
}});
- registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- return new FingerprintManager(ctx);
- }});
-
registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
@@ -562,6 +550,13 @@
return new TelephonyManager(ctx.getOuterContext());
}});
+ registerService(TELECOMM_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(TELECOMM_SERVICE);
+ return new TelecommManager(ctx.getOuterContext(),
+ ITelecommService.Stub.asInterface(b));
+ }});
+
registerService(UI_MODE_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new UiModeManager();
@@ -689,6 +684,7 @@
return new MediaSessionManager(ctx);
}
});
+
registerService(TRUST_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(TRUST_SERVICE);
@@ -696,6 +692,14 @@
}
});
+ registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(FINGERPRINT_SERVICE);
+ IFingerprintService service = IFingerprintService.Stub.asInterface(b);
+ return new FingerprintManager(ctx.getOuterContext(), service);
+ }
+ });
+
registerService(TV_INPUT_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder iBinder = ServiceManager.getService(TV_INPUT_SERVICE);
@@ -714,10 +718,10 @@
return new UsageStatsManager(ctx.getOuterContext());
}});
- registerService(TASK_SERVICE, new ServiceFetcher() {
+ registerService(JOB_SCHEDULER_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(TASK_SERVICE);
- return new TaskManagerImpl(ITaskManager.Stub.asInterface(b));
+ IBinder b = ServiceManager.getService(JOB_SCHEDULER_SERVICE);
+ return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
}});
}
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 4b052e7..365cc8e 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -53,18 +53,38 @@
private boolean mIsCanceled;
private ObjectAnimator mBackgroundAnimator;
private boolean mIsExitTransitionComplete;
+ private boolean mIsReadyForTransition;
+ private Bundle mSharedElementsBundle;
public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
- ArrayList<String> sharedElementNames,
- ArrayList<String> acceptedNames, ArrayList<String> mappedNames) {
- super(activity.getWindow(), sharedElementNames, acceptedNames, mappedNames,
- getListener(activity, acceptedNames), acceptedNames != null);
+ ArrayList<String> sharedElementNames, boolean isReturning) {
+ super(activity.getWindow(), sharedElementNames,
+ getListener(activity, isReturning), isReturning);
mActivity = activity;
setResultReceiver(resultReceiver);
prepareEnter();
Bundle resultReceiverBundle = new Bundle();
resultReceiverBundle.putParcelable(KEY_REMOTE_RECEIVER, this);
mResultReceiver.send(MSG_SET_REMOTE_RECEIVER, resultReceiverBundle);
+ getDecor().getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ if (mIsReadyForTransition) {
+ getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+ }
+ return mIsReadyForTransition;
+ }
+ });
+ }
+
+ public void viewsReady(ArrayList<String> accepted, ArrayList<String> localNames) {
+ if (mIsReadyForTransition) {
+ return;
+ }
+ super.viewsReady(accepted, localNames);
+
+ mIsReadyForTransition = true;
if (mIsReturning) {
mHandler = new Handler() {
@Override
@@ -75,11 +95,27 @@
mHandler.sendEmptyMessageDelayed(MSG_CANCEL, MAX_WAIT_MS);
send(MSG_SEND_SHARED_ELEMENT_DESTINATION, null);
}
+ setViewVisibility(mSharedElements, View.INVISIBLE);
+ if (getViewsTransition() != null) {
+ setViewVisibility(mTransitioningViews, View.INVISIBLE);
+ }
+ if (mSharedElementsBundle != null) {
+ onTakeSharedElements();
+ }
}
private void sendSharedElementDestination() {
ViewGroup decor = getDecor();
- if (!decor.isLayoutRequested()) {
+ boolean allReady = !decor.isLayoutRequested();
+ if (allReady) {
+ for (int i = 0; i < mSharedElements.size(); i++) {
+ if (mSharedElements.get(i).isLayoutRequested()) {
+ allReady = false;
+ break;
+ }
+ }
+ }
+ if (allReady) {
Bundle state = captureSharedElementState();
mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
} else {
@@ -88,15 +124,18 @@
@Override
public boolean onPreDraw() {
getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+ Bundle state = captureSharedElementState();
+ mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state);
return true;
}
});
}
+ if (allowOverlappingTransitions()) {
+ startEnterTransitionOnly();
+ }
}
- private static SharedElementListener getListener(Activity activity,
- ArrayList<String> acceptedNames) {
- boolean isReturning = acceptedNames != null;
+ private static SharedElementListener getListener(Activity activity, boolean isReturning) {
return isReturning ? activity.mExitTransitionListener : activity.mEnterTransitionListener;
}
@@ -108,7 +147,8 @@
if (mHandler != null) {
mHandler.removeMessages(MSG_CANCEL);
}
- onTakeSharedElements(resultData);
+ mSharedElementsBundle = resultData;
+ onTakeSharedElements();
}
break;
case MSG_EXIT_TRANSITION_COMPLETE:
@@ -139,7 +179,7 @@
mSharedElementNames.clear();
mSharedElements.clear();
mAllSharedElementNames.clear();
- onTakeSharedElements(null);
+ startSharedElementTransition(null);
onRemoteExitTransitionComplete();
}
}
@@ -149,10 +189,6 @@
}
protected void prepareEnter() {
- setViewVisibility(mSharedElements, View.INVISIBLE);
- if (getViewsTransition() != null) {
- setViewVisibility(mTransitioningViews, View.INVISIBLE);
- }
mActivity.overridePendingTransition(0, 0);
if (!mIsReturning) {
mActivity.convertToTranslucent(null, null);
@@ -185,7 +221,7 @@
}
}
- protected void onTakeSharedElements(Bundle sharedElementState) {
+ private void startSharedElementTransition(Bundle sharedElementState) {
setEpicenter();
// Remove rejected shared elements
ArrayList<String> rejectedNames = new ArrayList<String>(mAllSharedElementNames);
@@ -202,7 +238,7 @@
setSharedElementState(sharedElementState, sharedElementSnapshots);
requestLayoutForSharedElements();
- boolean startEnterTransition = allowOverlappingTransitions();
+ boolean startEnterTransition = allowOverlappingTransitions() && !mIsReturning;
boolean startSharedElementTransition = true;
Transition transition = beginTransition(startEnterTransition, startSharedElementTransition);
@@ -218,6 +254,29 @@
mResultReceiver = null; // all done sending messages.
}
+ private void onTakeSharedElements() {
+ if (!mIsReadyForTransition || mSharedElementsBundle == null) {
+ return;
+ }
+ final Bundle sharedElementState = mSharedElementsBundle;
+ mSharedElementsBundle = null;
+ getDecor().getViewTreeObserver()
+ .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+ startTransition(new Runnable() {
+ @Override
+ public void run() {
+ startSharedElementTransition(sharedElementState);
+ }
+ });
+ return false;
+ }
+ });
+ getDecor().invalidate();
+ }
+
private void requestLayoutForSharedElements() {
int numSharedElements = mSharedElements.size();
for (int i = 0; i < numSharedElements; i++) {
@@ -242,9 +301,10 @@
if (transition == null) {
sharedElementTransitionStarted();
} else {
- transition.addListener(new Transition.TransitionListenerAdapter() {
+ transition.addListener(new ContinueTransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
+ super.onTransitionStart(transition);
transition.removeListener(this);
sharedElementTransitionStarted();
}
@@ -252,12 +312,17 @@
}
}
if (transition != null) {
+ if (sharedElementTransition == null) {
+ transition.addListener(new ContinueTransitionListener());
+ }
TransitionManager.beginDelayedTransition(getDecor(), transition);
if (startSharedElementTransition && !mSharedElementNames.isEmpty()) {
mSharedElements.get(0).invalidate();
} else if (startEnterTransition && !mTransitioningViews.isEmpty()) {
mTransitioningViews.get(0).invalidate();
}
+ } else {
+ transitionStarted();
}
return transition;
}
@@ -276,7 +341,7 @@
if (background != null) {
background = background.mutate();
mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 255);
- mBackgroundAnimator.setDuration(FADE_BACKGROUND_DURATION_MS);
+ mBackgroundAnimator.setDuration(getFadeDuration());
mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -299,8 +364,8 @@
}
public void stop() {
+ makeOpaque();
mHasStopped = true;
- mActivity = null;
mIsCanceled = true;
mResultReceiver = null;
if (mBackgroundAnimator != null) {
@@ -310,7 +375,7 @@
}
private void makeOpaque() {
- if (!mHasStopped) {
+ if (!mHasStopped && mActivity != null) {
mActivity.convertFromTranslucent();
mActivity = null;
}
@@ -348,11 +413,21 @@
protected void onRemoteExitTransitionComplete() {
if (!allowOverlappingTransitions()) {
- boolean startEnterTransition = true;
- boolean startSharedElementTransition = false;
- Transition transition = beginTransition(startEnterTransition,
- startSharedElementTransition);
- startEnterTransition(transition);
+ startEnterTransitionOnly();
}
}
+
+ private void startEnterTransitionOnly() {
+ startTransition(new Runnable() {
+ @Override
+ public void run() {
+ setEpicenter();
+ boolean startEnterTransition = true;
+ boolean startSharedElementTransition = false;
+ Transition transition = beginTransition(startEnterTransition,
+ startSharedElementTransition);
+ startEnterTransition(transition);
+ }
+ });
+ }
}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index ba1638ff..9f3dbdc 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -19,6 +19,7 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Intent;
+import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -27,6 +28,7 @@
import android.transition.Transition;
import android.transition.TransitionManager;
import android.view.View;
+import android.view.ViewGroupOverlay;
import android.view.ViewTreeObserver;
import java.util.ArrayList;
@@ -60,10 +62,10 @@
private boolean mIsHidden;
- private boolean mExitTransitionStarted;
-
private Bundle mExitSharedElementBundle;
+ private ArrayList<View> mSharedElementSnapshots;
+
public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
ArrayList<String> accepted, ArrayList<String> mapped, boolean isReturning) {
super(activity.getWindow(), names, accepted, mapped, getListener(activity, isReturning),
@@ -106,30 +108,83 @@
break;
case MSG_SHARED_ELEMENT_DESTINATION:
mExitSharedElementBundle = resultData;
- if (mExitTransitionStarted) {
- startSharedElementExit();
- }
+ sharedElementExitBack();
break;
}
}
- private void startSharedElementExit() {
+ private void sharedElementExitBack() {
if (!mSharedElements.isEmpty() && getSharedElementTransition() != null) {
- Transition transition = getSharedElementExitTransition();
- TransitionManager.beginDelayedTransition(getDecor(), transition);
- ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
- mSharedElementNames);
- setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots);
+ startTransition(new Runnable() {
+ public void run() {
+ startSharedElementExit();
+ }
+ });
}
}
+ private void startSharedElementExit() {
+ Transition transition = getSharedElementExitTransition();
+ final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle,
+ mSharedElementNames);
+ mSharedElementSnapshots = createSnapshots(mExitSharedElementBundle, mSharedElementNames);
+ transition.addListener(new Transition.TransitionListenerAdapter() {
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ setViewVisibility(mSharedElements, View.INVISIBLE);
+ ViewGroupOverlay overlay = getDecor().getOverlay();
+ if (mSharedElementSnapshots != null) {
+ for (int i = 0; i < mSharedElementSnapshots.size(); i++) {
+ overlay.add(mSharedElementSnapshots.get(i));
+ }
+ }
+ }
+ });
+ getDecor().getViewTreeObserver()
+ .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+ setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots);
+ return true;
+ }
+ });
+ TransitionManager.beginDelayedTransition(getDecor(), transition);
+ getDecor().invalidate();
+ }
+
+ private static ArrayList<View> copySnapshots(ArrayList<View> snapshots) {
+ ArrayList<View> copy = new ArrayList<View>(snapshots.size());
+ for (int i = 0; i < snapshots.size(); i++) {
+ View view = snapshots.get(i);
+ View viewCopy = new View(view.getContext());
+ viewCopy.setBackground(view.getBackground());
+ copy.add(viewCopy);
+ }
+ return copy;
+ }
+
private void hideSharedElements() {
- setViewVisibility(mSharedElements, View.INVISIBLE);
+ if (!mIsHidden) {
+ setViewVisibility(mSharedElements, View.INVISIBLE);
+ }
+ if (mSharedElementSnapshots != null) {
+ ViewGroupOverlay overlay = getDecor().getOverlay();
+ for (int i = 0; i < mSharedElementSnapshots.size(); i++) {
+ overlay.remove(mSharedElementSnapshots.get(i));
+ }
+ mSharedElementSnapshots = null;
+ }
finishIfNecessary();
}
public void startExit() {
- beginTransitions();
+ startTransition(new Runnable() {
+ @Override
+ public void run() {
+ beginTransitions();
+ }
+ });
setViewVisibility(mTransitioningViews, View.INVISIBLE);
}
@@ -159,29 +214,25 @@
}
}
}, options);
+ startTransition(new Runnable() {
+ @Override
+ public void run() {
+ startExitTransition();
+ }
+ });
+ }
+
+ private void startExitTransition() {
Transition sharedElementTransition = mSharedElements.isEmpty()
? null : getSharedElementTransition();
if (sharedElementTransition == null) {
sharedElementTransitionComplete();
}
- Transition transition = mergeTransitions(sharedElementTransition, getExitTransition());
- if (transition == null) {
- mExitTransitionStarted = true;
- } else {
+ Transition transition = mergeTransitions(sharedElementTransition,
+ getExitTransition());
+ if (transition != null) {
TransitionManager.beginDelayedTransition(getDecor(), transition);
setViewVisibility(mTransitioningViews, View.INVISIBLE);
- getDecor().getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
- mExitTransitionStarted = true;
- if (mExitSharedElementBundle != null) {
- startSharedElementExit();
- }
- notifyComplete();
- return true;
- }
- });
}
}
@@ -199,7 +250,7 @@
}
}
});
- mBackgroundAnimator.setDuration(FADE_BACKGROUND_DURATION_MS);
+ mBackgroundAnimator.setDuration(getFadeDuration());
mBackgroundAnimator.start();
}
}
@@ -212,7 +263,7 @@
if (viewsTransition == null) {
exitTransitionComplete();
} else {
- viewsTransition.addListener(new Transition.TransitionListenerAdapter() {
+ viewsTransition.addListener(new ContinueTransitionListener() {
@Override
public void onTransitionEnd(Transition transition) {
exitTransitionComplete();
@@ -238,7 +289,7 @@
if (sharedElementTransition == null) {
sharedElementTransitionComplete();
} else {
- sharedElementTransition.addListener(new Transition.TransitionListenerAdapter() {
+ sharedElementTransition.addListener(new ContinueTransitionListener() {
@Override
public void onTransitionEnd(Transition transition) {
sharedElementTransitionComplete();
@@ -257,7 +308,6 @@
Transition viewsTransition = getExitTransition();
Transition transition = mergeTransitions(sharedElementTransition, viewsTransition);
- mExitTransitionStarted = true;
if (transition != null) {
TransitionManager.beginDelayedTransition(getDecor(), transition);
}
@@ -269,15 +319,31 @@
}
protected boolean isReadyToNotify() {
- return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady
- && mExitTransitionStarted;
+ return mSharedElementBundle != null && mResultReceiver != null && mIsBackgroundReady;
}
private void sharedElementTransitionComplete() {
- mSharedElementBundle = captureSharedElementState();
+ mSharedElementBundle = mExitSharedElementBundle == null
+ ? captureSharedElementState() : captureExitSharedElementsState();
notifyComplete();
}
+ private Bundle captureExitSharedElementsState() {
+ Bundle bundle = new Bundle();
+ Rect bounds = new Rect();
+ for (int i = 0; i < mSharedElementNames.size(); i++) {
+ String name = mSharedElementNames.get(i);
+ Bundle sharedElementState = mExitSharedElementBundle.getBundle(name);
+ if (sharedElementState != null) {
+ bundle.putBundle(name, sharedElementState);
+ } else {
+ View view = mSharedElements.get(i);
+ captureSharedElementState(view, name, bundle, bounds);
+ }
+ }
+ return bundle;
+ }
+
protected void notifyComplete() {
if (isReadyToNotify()) {
if (!mSharedElementNotified) {
@@ -294,8 +360,7 @@
}
private void finishIfNecessary() {
- if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty()
- || mSharedElements.get(0).getVisibility() == View.INVISIBLE)) {
+ if (mIsReturning && mExitNotified && mActivity != null && mSharedElementSnapshots == null) {
mActivity.finish();
mActivity.overridePendingTransition(0, 0);
mActivity = null;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 76f9d97..b8f1962 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1494,7 +1494,7 @@
return false;
}
final BackStackRecord bss = mBackStack.remove(last);
- bss.popFromBackStack(true);
+ bss.popFromBackStack(true, null);
reportBackStackChanged();
} else {
int index = -1;
@@ -1538,9 +1538,10 @@
states.add(mBackStack.remove(i));
}
final int LAST = states.size()-1;
+ BackStackRecord.TransitionState state = null;
for (int i=0; i<=LAST; i++) {
if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
- states.get(i).popFromBackStack(i == LAST);
+ state = states.get(i).popFromBackStack(i == LAST, state);
}
reportBackStackChanged();
}
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 6e99899..7479ecd 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -1,5 +1,8 @@
package android.app;
+import android.util.Pair;
+import android.view.View;
+
/**
* API for performing a set of Fragment operations.
*
@@ -169,6 +172,36 @@
public abstract FragmentTransaction setTransition(int transit);
/**
+ * Set a {@link android.transition.Transition} resource id to use with this transaction.
+ * <var>transitionId</var> will be played for fragments when going forward and when popping
+ * the back stack.
+ * @param sceneRootId The ID of the element acting as the scene root for the transition.
+ * This should be a ViewGroup containing all Fragments in the transaction.
+ * @param transitionId The resource ID for the Transition used during the Fragment transaction.
+ */
+ public abstract FragmentTransaction setCustomTransition(int sceneRootId, int transitionId);
+
+ /**
+ * Used with {@link #setCustomTransition(int, int)} to map a View from a removed or hidden
+ * Fragment to a View from a shown or added Fragment.
+ * <var>sharedElement</var> must have a unique viewName in the View hierarchy.
+ * @param sharedElement A View in a disappearing Fragment to match with a View in an
+ * appearing Fragment.
+ * @param name The viewName for a View in an appearing Fragment to match to the shared
+ * element.
+ */
+ public abstract FragmentTransaction setSharedElement(View sharedElement, String name);
+
+ /**
+ * Used with {@link #setCustomTransition(int, int)} to map multiple Views from removed or hidden
+ * Fragments to a Views from a shown or added Fragments. Views in
+ * <var>sharedElements</var> must have unique viewNames in the View hierarchy.
+ * @param sharedElements Pairs of Views in disappearing Fragments to viewNames in
+ * appearing Fragments.
+ */
+ public abstract FragmentTransaction setSharedElements(Pair<View, String>... sharedElements);
+
+ /**
* Set a custom style resource that will be used for resolving transit
* animations.
*/
diff --git a/core/java/android/app/JobSchedulerImpl.java b/core/java/android/app/JobSchedulerImpl.java
new file mode 100644
index 0000000..09038d5
--- /dev/null
+++ b/core/java/android/app/JobSchedulerImpl.java
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+// in android.app so ContextImpl has package access
+package android.app;
+
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.app.job.IJobScheduler;
+import android.os.RemoteException;
+
+import java.util.List;
+
+
+/**
+ * Concrete implementation of the JobScheduler interface
+ * @hide
+ */
+public class JobSchedulerImpl extends JobScheduler {
+ IJobScheduler mBinder;
+
+ /* package */ JobSchedulerImpl(IJobScheduler binder) {
+ mBinder = binder;
+ }
+
+ @Override
+ public int schedule(JobInfo job) {
+ try {
+ return mBinder.schedule(job);
+ } catch (RemoteException e) {
+ return JobScheduler.RESULT_FAILURE;
+ }
+ }
+
+ @Override
+ public void cancel(int jobId) {
+ try {
+ mBinder.cancel(jobId);
+ } catch (RemoteException e) {}
+
+ }
+
+ @Override
+ public void cancelAll() {
+ try {
+ mBinder.cancelAll();
+ } catch (RemoteException e) {}
+
+ }
+
+ @Override
+ public List<JobInfo> getAllPendingJobs() {
+ try {
+ return mBinder.getAllPendingJobs();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5ac2a33..b94fd41 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -17,11 +17,12 @@
package android.app;
import android.annotation.IntDef;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
@@ -29,7 +30,6 @@
import android.media.session.MediaSessionToken;
import android.net.Uri;
import android.os.BadParcelableException;
-import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -74,6 +74,15 @@
private static final String TAG = "Notification";
/**
+ * An activity that provides a user interface for adjusting notification preferences for its
+ * containing application. Optional but recommended for apps that post
+ * {@link android.app.Notification Notifications}.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String INTENT_CATEGORY_NOTIFICATION_PREFERENCES
+ = "android.intent.category.NOTIFICATION_PREFERENCES";
+
+ /**
* Use all default values (where applicable).
*/
public static final int DEFAULT_ALL = ~0;
@@ -2499,7 +2508,7 @@
/**
* @return Whether we are currently building a notification from a legacy (an app that
- * doesn't create quantum notifications by itself) app.
+ * doesn't create material notifications by itself) app.
*/
private boolean isLegacy() {
return mColorUtil != null;
@@ -2557,7 +2566,7 @@
R.id.icon,
true,
-1,
- mColor,
+ resolveColor(),
PorterDuff.Mode.SRC_ATOP,
-1);
}
@@ -2584,17 +2593,22 @@
R.id.right_icon,
true,
-1,
- mColor,
+ resolveColor(),
PorterDuff.Mode.SRC_ATOP,
-1);
}
}
+ private int sanitizeColor() {
+ if (mColor != COLOR_DEFAULT) {
+ mColor |= 0xFF000000; // no alpha for custom colors
+ }
+ return mColor;
+ }
+
private int resolveColor() {
if (mColor == COLOR_DEFAULT) {
- mColor = mContext.getResources().getColor(R.color.notification_icon_bg_color);
- } else {
- mColor |= 0xFF000000; // no alpha for custom colors
+ return mContext.getResources().getColor(R.color.notification_icon_bg_color);
}
return mColor;
}
@@ -2610,7 +2624,7 @@
n.iconLevel = mSmallIconLevel;
n.number = mNumber;
- n.color = resolveColor();
+ n.color = sanitizeColor();
n.contentView = makeContentView();
n.contentIntent = mContentIntent;
@@ -2719,31 +2733,31 @@
private int getBaseLayoutResource() {
- return R.layout.notification_template_quantum_base;
+ return R.layout.notification_template_material_base;
}
private int getBigBaseLayoutResource() {
- return R.layout.notification_template_quantum_big_base;
+ return R.layout.notification_template_material_big_base;
}
private int getBigPictureLayoutResource() {
- return R.layout.notification_template_quantum_big_picture;
+ return R.layout.notification_template_material_big_picture;
}
private int getBigTextLayoutResource() {
- return R.layout.notification_template_quantum_big_text;
+ return R.layout.notification_template_material_big_text;
}
private int getInboxLayoutResource() {
- return R.layout.notification_template_quantum_inbox;
+ return R.layout.notification_template_material_inbox;
}
private int getActionLayoutResource() {
- return R.layout.notification_quantum_action;
+ return R.layout.notification_material_action;
}
private int getActionTombstoneLayoutResource() {
- return R.layout.notification_quantum_action_tombstone;
+ return R.layout.notification_material_action_tombstone;
}
}
@@ -2853,16 +2867,16 @@
/**
* Helper class for generating large-format notifications that include a large image attachment.
*
- * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
+ * Here's how you'd set the <code>BigPictureStyle</code> on a notification:
* <pre class="prettyprint">
- * Notification noti = new Notification.BigPictureStyle(
- * new Notification.Builder()
- * .setContentTitle("New photo from " + sender.toString())
- * .setContentText(subject)
- * .setSmallIcon(R.drawable.new_post)
- * .setLargeIcon(aBitmap))
- * .bigPicture(aBigBitmap)
- * .build();
+ * Notification notif = new Notification.Builder(mContext)
+ * .setContentTitle("New photo from " + sender.toString())
+ * .setContentText(subject)
+ * .setSmallIcon(R.drawable.new_post)
+ * .setLargeIcon(aBitmap)
+ * .setStyle(new Notification.BigPictureStyle()
+ * .bigPicture(aBigBitmap))
+ * .build();
* </pre>
*
* @see Notification#bigContentView
@@ -2949,16 +2963,16 @@
/**
* Helper class for generating large-format notifications that include a lot of text.
*
- * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
+ * Here's how you'd set the <code>BigTextStyle</code> on a notification:
* <pre class="prettyprint">
- * Notification noti = new Notification.BigTextStyle(
- * new Notification.Builder()
- * .setContentTitle("New mail from " + sender.toString())
- * .setContentText(subject)
- * .setSmallIcon(R.drawable.new_mail)
- * .setLargeIcon(aBitmap))
- * .bigText(aVeryLongString)
- * .build();
+ * Notification notif = new Notification.Builder(mContext)
+ * .setContentTitle("New mail from " + sender.toString())
+ * .setContentText(subject)
+ * .setSmallIcon(R.drawable.new_mail)
+ * .setLargeIcon(aBitmap)
+ * .setStyle(new Notification.BigTextStyle()
+ * .bigText(aVeryLongString))
+ * .build();
* </pre>
*
* @see Notification#bigContentView
@@ -3043,19 +3057,19 @@
/**
* Helper class for generating large-format notifications that include a list of (up to 5) strings.
*
- * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
+ * Here's how you'd set the <code>InboxStyle</code> on a notification:
* <pre class="prettyprint">
- * Notification noti = new Notification.InboxStyle(
- * new Notification.Builder()
- * .setContentTitle("5 New mails from " + sender.toString())
- * .setContentText(subject)
- * .setSmallIcon(R.drawable.new_mail)
- * .setLargeIcon(aBitmap))
- * .addLine(str1)
- * .addLine(str2)
- * .setContentTitle("")
- * .setSummaryText("+3 more")
- * .build();
+ * Notification notif = new Notification.Builder(mContext)
+ * .setContentTitle("5 New mails from " + sender.toString())
+ * .setContentText(subject)
+ * .setSmallIcon(R.drawable.new_mail)
+ * .setLargeIcon(aBitmap)
+ * .setStyle(new Notification.InboxStyle()
+ * .addLine(str1)
+ * .addLine(str2)
+ * .setContentTitle("")
+ * .setSummaryText("+3 more"))
+ * .build();
* </pre>
*
* @see Notification#bigContentView
@@ -3238,7 +3252,7 @@
private RemoteViews generateMediaActionButton(Action action) {
final boolean tombstone = (action.actionIntent == null);
RemoteViews button = new RemoteViews(mBuilder.mContext.getPackageName(),
- R.layout.notification_quantum_media_action);
+ R.layout.notification_material_media_action);
button.setImageViewResource(R.id.action0, action.icon);
if (!tombstone) {
button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
@@ -3249,7 +3263,7 @@
private RemoteViews makeMediaContentView() {
RemoteViews view = mBuilder.applyStandardTemplate(
- R.layout.notification_template_quantum_media, true /* 1U */);
+ R.layout.notification_template_material_media, true /* 1U */);
final int numActions = mBuilder.mActions.size();
final int N = mActionsToShowInCompact == null
@@ -3274,7 +3288,7 @@
private RemoteViews makeMediaBigContentView() {
RemoteViews big = mBuilder.applyStandardTemplate(
- R.layout.notification_template_quantum_big_media, false);
+ R.layout.notification_template_material_big_media, false);
final int N = Math.min(mBuilder.mActions.size(), MAX_MEDIA_BUTTONS);
if (N > 0) {
@@ -3605,14 +3619,16 @@
* .build();</pre>
*
* <p>The activity to launch needs to allow embedding, must be exported, and
- * should have an empty task affinity.
+ * should have an empty task affinity. It is also recommended to use the device
+ * default light theme.
*
* <p>Example AndroidManifest.xml entry:
* <pre class="prettyprint">
* <activity android:name="com.example.MyDisplayActivity"
* android:exported="true"
* android:allowEmbedded="true"
- * android:taskAffinity="" /></pre>
+ * android:taskAffinity=""
+ * android:theme="@android:style/Theme.DeviceDefault.Light" /></pre>
*
* @param intent the {@link PendingIntent} for an activity
* @return this object for method chaining
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 33c3409..261b15d 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -253,6 +253,7 @@
* for more information on these schemes.
*/
public final static String SUGGEST_COLUMN_ICON_1 = "suggest_icon_1";
+
/**
* Column name for suggestions cursor. <i>Optional.</i> If your cursor includes this column,
* then all suggestions will be provided in a format that includes space for two small icons,
@@ -269,6 +270,24 @@
* for more information on these schemes.
*/
public final static String SUGGEST_COLUMN_ICON_2 = "suggest_icon_2";
+
+ /**
+ * Column name for suggestions cursor. <i>Optional.</i> If your cursor includes this column,
+ * then the image will be displayed when forming the suggestion. The suggested dimension for
+ * the image is 270x400 px for portrait mode and 400x225 px for landscape mode. The data in the
+ * column must be a resource ID of a drawable, or a URI in one of the following formats:
+ *
+ * <ul>
+ * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+ * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})</li>
+ * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+ * </ul>
+ *
+ * See {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String)}
+ * for more information on these schemes.
+ */
+ public final static String SUGGEST_COLUMN_RESULT_CARD_IMAGE = "suggest_result_card_image";
+
/**
* Column name for suggestions cursor. <i>Optional.</i> If this column exists <i>and</i>
* this element exists at the given row, this is the action that will be used when
@@ -279,6 +298,7 @@
* it from the cursor.
*/
public final static String SUGGEST_COLUMN_INTENT_ACTION = "suggest_intent_action";
+
/**
* Column name for suggestions cursor. <i>Optional.</i> If this column exists <i>and</i>
* this element exists at the given row, this is the data that will be used when
@@ -289,6 +309,7 @@
* it is more efficient to specify it using XML metadata and omit it from the cursor.
*/
public final static String SUGGEST_COLUMN_INTENT_DATA = "suggest_intent_data";
+
/**
* Column name for suggestions cursor. <i>Optional.</i> If this column exists <i>and</i>
* this element exists at the given row, this is the data that will be used when
@@ -297,6 +318,7 @@
* an extra under the key {@link #EXTRA_DATA_KEY}.
*/
public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
+
/**
* Column name for suggestions cursor. <i>Optional.</i> If this column exists <i>and</i>
* this element exists at the given row, then "/" and this value will be appended to the data
@@ -304,6 +326,7 @@
* appropriate base string.
*/
public final static String SUGGEST_COLUMN_INTENT_DATA_ID = "suggest_intent_data_id";
+
/**
* Column name for suggestions cursor. <i>Required if action is
* {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH}, optional otherwise.</i> If this
@@ -331,6 +354,89 @@
"suggest_spinner_while_refreshing";
/**
+ * Column name for suggestions cursor. <i>Optional.</i> If your content is media type, you
+ * should provide this column so search app could understand more about your content. The data
+ * in the column must specify the MIME type of the content.
+ */
+ public final static String SUGGEST_COLUMN_CONTENT_TYPE = "suggest_content_type";
+
+ /**
+ * Column name for suggestions cursor. <i>Optional.</i> If your content is media type, you
+ * should provide this column to specify whether your content is live media such as live video
+ * or live audio. The value in the column is of integer type with value of either 0 indicating
+ * non-live content or 1 indicating live content.
+ */
+ public final static String SUGGEST_COLUMN_IS_LIVE = "suggest_is_live";
+
+ /**
+ * Column name for suggestions cursor. <i>Optional.</i> If your content is video, you should
+ * provide this column to specify the number of vertical lines. The data in the column is of
+ * integer type.
+ */
+ public final static String SUGGEST_COLUMN_VIDEO_WIDTH = "suggest_video_width";
+
+ /**
+ * Column name for suggestions cursor. <i>Optional.</i> If your content is video, you should
+ * provide this column to specify the number of horizontal lines. The data in the column is of
+ * integer type.
+ */
+ public final static String SUGGEST_COLUMN_VIDEO_HEIGHT = "suggest_video_height";
+
+ /**
+ * Column name for suggestions cursor. <i>Optional.</i> If your content contains audio, you
+ * should provide this column to specify the audio channel configuration. The data in the
+ * column is string with format like "channels.subchannels" such as "1.0" or "5.1".
+ */
+ public final static String SUGGEST_COLUMN_AUDIO_CHANNEL_CONFIG = "suggest_audio_channel_config";
+
+ /**
+ * Column name for suggestions cursor. <i>Optional.</i> If your content is purchasable, you
+ * should provide this column to specify the displayable string representation of the purchase
+ * price of your content including the currency and the amount. If it's free, you should
+ * provide localized string to specify that it's free. This column can be omitted if the content
+ * is not applicable to purchase.
+ */
+ public final static String SUGGEST_COLUMN_PURCHASE_PRICE = "suggest_purchase_price";
+
+ /**
+ * Column name for suggestions cursor. <i>Optional.</i> If your content is rentable, you
+ * should provide this column to specify the displayable string representation of the rental
+ * price of your content including the currency and the amount. If it's free, you should
+ * provide localized string to specify that it's free. This column can be ommitted if the
+ * content is not applicable to rent.
+ */
+ public final static String SUGGEST_COLUMN_RENTAL_PRICE = "suggest_rental_price";
+
+ /**
+ * Column name for suggestions cursor. <i>Optional.</i> If your content has a rating, you
+ * should provide this column to specify the rating style of your content. The data in the
+ * column must be one of the constant values specified in {@link android.media.Rating}
+ */
+ public final static String SUGGEST_COLUMN_RATING_STYLE = "suggest_rating_style";
+
+ /**
+ * Column name for suggestions cursor. <i>Optional.</i> If your content has a rating, you
+ * should provide this column to specify the rating score of your content. The data in the
+ * column is of float type. See {@link android.media.Rating} about valid rating scores for each
+ * rating style.
+ */
+ public final static String SUGGEST_COLUMN_RATING_SCORE = "suggest_rating_score";
+
+ /**
+ * Column name for suggestions cursor. <i>Optional.</i> If your content is video or audio and
+ * has a known production year, you should provide this column to specify the production year
+ * of your content. The data in the column is of integer type.
+ */
+ public final static String SUGGEST_COLUMN_PRODUCTION_YEAR = "suggest_production_year";
+
+ /**
+ * Column name for suggestions cursor. <i>Optional.</i> If your content is video or audio, you
+ * should provide this column to specify the duration of your content in milliseconds. The data
+ * in the column is of long type.
+ */
+ public final static String SUGGEST_COLUMN_DURATION = "suggest_duration";
+
+ /**
* Column name for suggestions cursor. <i>Optional.</i> This column is used to specify
* additional flags per item. Multiple flags can be specified.
* <p>
diff --git a/core/java/android/app/TaskManagerImpl.java b/core/java/android/app/TaskManagerImpl.java
deleted file mode 100644
index f42839e..0000000
--- a/core/java/android/app/TaskManagerImpl.java
+++ /dev/null
@@ -1,62 +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.
- */
-
-// in android.app so ContextImpl has package access
-package android.app;
-
-import android.app.task.ITaskManager;
-import android.app.task.Task;
-import android.app.task.TaskManager;
-
-import java.util.List;
-
-
-/**
- * Concrete implementation of the TaskManager interface
- * @hide
- */
-public class TaskManagerImpl extends TaskManager {
- ITaskManager mBinder;
-
- /* package */ TaskManagerImpl(ITaskManager binder) {
- mBinder = binder;
- }
-
- @Override
- public int schedule(Task task) {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public void cancel(int taskId) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void cancelAll() {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public List<Task> getAllPendingTasks() {
- // TODO Auto-generated method stub
- return null;
- }
-
-}
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 85e970c..0d947217 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -293,7 +293,7 @@
IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName,
IVoiceInteractorCallback callback) throws RemoteException {
- return interactor.startConfirmation(packageName, callback, mCommand, mArgs);
+ return interactor.startCommand(packageName, callback, mCommand, mArgs);
}
}
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 2cc15e2..45a2625 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -16,6 +16,7 @@
package android.app.admin;
+import android.accounts.AccountManager;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Service;
@@ -165,15 +166,14 @@
= "android.app.action.ACTION_PASSWORD_EXPIRING";
/**
- * Broadcast Action: This broadcast is sent to the newly created profile when
- * the provisioning of a managed profile has completed successfully. It is used in both the
- * Profile Owner and the Device Owner provisioning.
+ * Broadcast Action: This broadcast is sent to indicate that provisioning of a managed profile
+ * or managed device has completed successfully.
*
- * <p>The broadcast is limited to the DeviceAdminReceiver component specified in the message
- * that started the provisioning. It is also limited to the managed profile.
- *
- * <p> The intent may contain the extra
- * {@link DevicePolicyManager#EXTRA_PROVISIONING_EMAIL_ADDRESS}.
+ * <p>The broadcast is limited to the profile that will be managed by the application that
+ * requested provisioning. In the device owner case the profile is the primary user.
+ * The broadcast will also be limited to the {@link DeviceAdminReceiver} component
+ * specified in the original intent or NFC bump that started the provisioning process
+ * (@see DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE).
*
* <p>Input: Nothing.</p>
* <p>Output: Nothing</p>
@@ -222,6 +222,12 @@
* Called after the administrator is first enabled, as a result of
* receiving {@link #ACTION_DEVICE_ADMIN_ENABLED}. At this point you
* can use {@link DevicePolicyManager} to set your desired policies.
+ *
+ * <p> If the admin is activated by a device owner, then the intent
+ * may contain private extras that are relevant to user setup.
+ * {@see DevicePolicyManager#createAndInitializeUser(ComponentName, String, String,
+ * ComponentName, Intent)}
+ *
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
*/
@@ -310,18 +316,23 @@
}
/**
- * Called on the new profile when managed profile provisioning has completed.
- * Managed profile provisioning is the process of setting up the device so that it has a
- * separate profile which is managed by the mobile device management(mdm) application that
- * triggered the provisioning.
+ * Called when provisioning of a managed profile or managed device has completed successfully.
*
- * <p>As part of provisioning a new profile is created, the mdm is moved to the new profile and
- * set as the owner of the profile so that it has full control over it.
- * This intent is only received by the mdm package that is set as profile owner during
- * provisioning.
+ * <p> As a prerequisit for the execution of this callback the (@link DeviceAdminReceiver} has
+ * to declare an intent filter for {@link #ACTION_PROFILE_PROVISIONING_COMPLETE}.
+ * Its component must also be specified in the {@link DevicePolicyManager#EXTRA_DEVICE_ADMIN}
+ * of the {@link DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE} intent that started the
+ * managed provisioning.
*
- * <p>Provisioning can be triggered via an intent with the action
- * android.managedprovisioning.ACTION_PROVISION_MANAGED_PROFILE.
+ * <p>When provisioning is complete, the managed profile is hidden until the profile owner
+ * calls {DevicePolicyManager#setProfileEnabled(ComponentName admin)}. Typically a profile
+ * owner will enable the profile when it has finished any additional setup such as adding an
+ * account by using the {@link AccountManager} and calling apis to bring the profile into the
+ * desired state.
+ *
+ * <p> Note that provisioning completes without waiting for any server interactions, so the
+ * profile owner needs to wait for data to be available if required (e.g android device ids or
+ * other data that is set as a result of server interactions).
*
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 57e0f63..e80c761 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -26,6 +26,8 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.RestrictionsManager;
+import android.media.AudioService;
+import android.net.ProxyInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Process;
@@ -98,17 +100,25 @@
/**
* Activity action: Starts the provisioning flow which sets up a managed profile.
- * This intent will typically be sent by a mobile device management application(mdm).
- * Managed profile provisioning creates a profile, moves the mdm to the profile,
- * sets the mdm as the profile owner and removes all non required applications from the profile.
- * As a profile owner the mdm than has full control over the managed profile.
*
- * <p>The intent must contain the extras {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} and
- * {@link #EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME}.
+ * <p>A managed profile allows data separation for example for the usage of a
+ * device as a personal and corporate device. The user which provisioning is started from and
+ * the managed profile share a launcher.
+ *
+ * <p>This intent will typically be sent by a mobile device management application (mdm).
+ * Provisioning adds a managed profile and sets the mdm as the profile owner who has full
+ * control over the profile
+ *
+ * <p>This intent must contain the extras {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}
+ * {@link #EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME} and {@link #EXTRA_DEVICE_ADMIN}.
*
* <p> When managed provisioning has completed, an intent of the type
* {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the
- * mdm app on the managed profile.
+ * managed profile. The intent is sent to the {@link DeviceAdminReceiver} specified in the
+ * {@link #EXTRA_DEVICE_ADMIN} exclusively.
+ *
+ * If provisioning fails, the managedProfile is removed so the device returns to its previous
+ * state.
*
* <p>Input: Nothing.</p>
* <p>Output: Nothing</p>
@@ -126,7 +136,7 @@
* @hide
*/
public static final String ACTION_PROVISIONING_USER_HAS_CONSENTED
- = "android.app.action.USER_HAS_CONSENTED";
+ = "android.app.action.ACTION_PROVISIONING_USER_HAS_CONSENTED";
/**
* A String extra holding the name of the package of the mobile device management application
@@ -134,7 +144,7 @@
* <p>Use with {@link #ACTION_PROVISION_MANAGED_PROFILE}.
*/
public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
- = "deviceAdminPackageName";
+ = "android.app.extra.deviceAdminPackageName";
/**
* An int extra used to identify that during the current setup process the user has already
@@ -154,7 +164,7 @@
* <p>Use with {@link #ACTION_PROVISION_MANAGED_PROFILE}
*/
public static final String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME
- = "defaultManagedProfileName";
+ = "android.app.extra.defaultManagedProfileName";
/**
* A String extra holding the email address of the profile that is created during managed
@@ -888,6 +898,9 @@
* {@link DeviceAdminInfo#USES_POLICY_EXPIRE_PASSWORD} to be able to call this
* method; if it has not, a security exception will be thrown.
*
+ * <p> Note that setting the password will automatically reset the expiration time for all
+ * active admins. Active admins do not need to explicitly call this method in that case.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param timeout The limit (in ms) that a password can remain in effect. A value of 0
* means there is no restriction (unlimited).
@@ -1276,6 +1289,32 @@
}
/**
+ * Set a network-independent global HTTP proxy. This is not normally what you want
+ * for typical HTTP proxies - they are generally network dependent. However if you're
+ * doing something unusual like general internal filtering this may be useful. On
+ * a private network where the proxy is not accessible, you may break HTTP using this.
+ *
+ * <p>This method requires the caller to be the device owner.
+ *
+ * <p>This proxy is only a recommendation and it is possible that some apps will ignore it.
+ * @see ProxyInfo
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated
+ * with.
+ * @param proxyInfo The a {@link ProxyInfo} object defining the new global
+ * HTTP proxy. A {@code null} value will clear the global HTTP proxy.
+ */
+ public void setRecommendedGlobalProxy(ComponentName admin, ProxyInfo proxyInfo) {
+ if (mService != null) {
+ try {
+ mService.setRecommendedGlobalProxy(admin, proxyInfo);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
* Returns the component name setting the global proxy.
* @return ComponentName object of the device admin that set the global proxy, or
* null if no admin has set the proxy.
@@ -1794,6 +1833,23 @@
return isDeviceOwnerApp(packageName);
}
+ /**
+ * Clears the current device owner. The caller must be the device owner.
+ *
+ * This function should be used cautiously as once it is called it cannot
+ * be undone. The device owner can only be set as a part of device setup
+ * before setup completes.
+ */
+ public void clearDeviceOwnerApp() {
+ if (mService != null) {
+ try {
+ mService.clearDeviceOwner(mContext.getPackageName());
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed to clear device owner");
+ }
+ }
+ }
+
/** @hide */
public String getDeviceOwner() {
if (mService != null) {
@@ -2006,6 +2062,8 @@
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param filter The {@link IntentFilter} the intent has to match to be also resolved in the
* other profile
+ * @param flags {@link DevicePolicyManager#FLAG_MANAGED_CAN_ACCESS_PARENT} and
+ * {@link DevicePolicyManager#FLAG_PARENT_CAN_ACCESS_MANAGED} are supported.
*/
public void addCrossProfileIntentFilter(ComponentName admin, IntentFilter filter, int flags) {
if (mService != null) {
@@ -2053,6 +2111,41 @@
}
/**
+ * Called by a device owner to create a user with the specified name. The UserHandle returned
+ * by this method should not be persisted as user handles are recycled as users are removed and
+ * created. If you need to persist an identifier for this user, use
+ * {@link UserManager#getSerialNumberForUser}. The new user will be started in the background
+ * immediately.
+ *
+ * <p> profileOwnerComponent is the {@link DeviceAdminReceiver} to be the profile owner as well
+ * as registered as an active admin on the new user. The profile owner package will be
+ * installed on the new user if it already is installed on the device.
+ *
+ * <p>If the optionalInitializeData is not null, then the extras will be passed to the
+ * profileOwnerComponent when onEnable is called.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param name the user's name
+ * @param ownerName the human readable name of the organisation associated with this DPM.
+ * @param profileOwnerComponent The {@link DeviceAdminReceiver} that will be an active admin on
+ * the user.
+ * @param adminExtras Extras that will be passed to onEnable of the admin receiver
+ * on the new user.
+ * @see UserHandle
+ * @return the UserHandle object for the created user, or null if the user could not be created.
+ */
+ public UserHandle createAndInitializeUser(ComponentName admin, String name, String ownerName,
+ ComponentName profileOwnerComponent, Bundle adminExtras) {
+ try {
+ return mService.createAndInitializeUser(admin, name, ownerName, profileOwnerComponent,
+ adminExtras);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not create a user", re);
+ }
+ return null;
+ }
+
+ /**
* Called by a device owner to remove a user and all associated data. The primary user can
* not be removed.
*
@@ -2349,4 +2442,37 @@
}
}
}
+
+ /**
+ * Called by profile or device owners to set the master volume mute on or off.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param on {@code true} to mute master volume, {@code false} to turn mute off.
+ */
+ public void setMasterVolumeMuted(ComponentName admin, boolean on) {
+ if (mService != null) {
+ try {
+ mService.setMasterVolumeMuted(admin, on);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed to setMasterMute on device policy service");
+ }
+ }
+ }
+
+ /**
+ * Called by profile or device owners to check whether the master volume mute is on or off.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return {@code true} if master volume is muted, {@code false} if it's not.
+ */
+ public boolean isMasterVolumeMuted(ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.isMasterVolumeMuted(admin);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed to get isMasterMute on device policy service");
+ }
+ }
+ return false;
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 7d7a312..a1caa21 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -20,6 +20,7 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.ProxyInfo;
import android.os.Bundle;
import android.os.RemoteCallback;
import android.os.UserHandle;
@@ -78,6 +79,7 @@
ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList, int userHandle);
ComponentName getGlobalProxyAdmin(int userHandle);
+ void setRecommendedGlobalProxy(in ComponentName admin, in ProxyInfo proxyInfo);
int setStorageEncryption(in ComponentName who, boolean encrypt, int userHandle);
boolean getStorageEncryption(in ComponentName who, int userHandle);
@@ -106,6 +108,7 @@
boolean isDeviceOwner(String packageName);
String getDeviceOwner();
String getDeviceOwnerName();
+ void clearDeviceOwner(String packageName);
boolean setProfileOwner(String packageName, String ownerName, int userHandle);
String getProfileOwner(int userHandle);
@@ -133,6 +136,7 @@
boolean isApplicationBlocked(in ComponentName admin, in String packageName);
UserHandle createUser(in ComponentName who, in String name);
+ UserHandle createAndInitializeUser(in ComponentName who, in String name, in String profileOwnerName, in ComponentName profileOwnerComponent, in Bundle adminExtras);
boolean removeUser(in ComponentName who, in UserHandle userHandle);
void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled);
@@ -144,4 +148,7 @@
void setGlobalSetting(in ComponentName who, in String setting, in String value);
void setSecureSetting(in ComponentName who, in String setting, in String value);
+
+ void setMasterVolumeMuted(in ComponentName admin, boolean on);
+ boolean isMasterVolumeMuted(in ComponentName admin);
}
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 46f082e..706ef04 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -228,19 +228,35 @@
}
/**
- * Get the package name of the next application with data in the backup store.
+ * Get the package name of the next application with data in the backup store, plus
+ * a description of the structure of the restored archive: either TYPE_KEY_VALUE for
+ * an original-API key/value dataset, or TYPE_FULL_STREAM for a tarball-type archive stream.
*
- * @return The name of one of the packages supplied to {@link #startRestore},
- * or "" (the empty string) if no more backup data is available,
- * or null if an error occurred (the restore should be aborted and rescheduled).
+ * <p>If the package name in the returned RestoreDescription object is the singleton
+ * {@link RestoreDescription#NO_MORE_PACKAGES}, it indicates that no further data is available
+ * in the current restore session: all packages described in startRestore() have been
+ * processed.
+ *
+ * <p>If this method returns {@code null}, it means that a transport-level error has
+ * occurred and the entire restore operation should be abandoned.
+ *
+ * @return A RestoreDescription object containing the name of one of the packages
+ * supplied to {@link #startRestore} plus an indicator of the data type of that
+ * restore data; or {@link RestoreDescription#NO_MORE_PACKAGES} to indicate that
+ * no more packages can be restored in this session; or {@code null} to indicate
+ * a transport-level error.
*/
- public String nextRestorePackage() {
+ public RestoreDescription nextRestorePackage() {
return null;
}
/**
- * Get the data for the application returned by {@link #nextRestorePackage}.
- * @param data An open, writable file into which the backup data should be stored.
+ * Get the data for the application returned by {@link #nextRestorePackage}, if that
+ * method reported {@link RestoreDescription#TYPE_KEY_VALUE} as its delivery type.
+ * If the package has only TYPE_FULL_STREAM data, then this method will return an
+ * error.
+ *
+ * @param data An open, writable file into which the key/value backup data should be stored.
* @return the same error codes as {@link #startRestore}.
*/
public int getRestoreData(ParcelFileDescriptor outFd) {
@@ -328,6 +344,59 @@
return BackupTransport.TRANSPORT_ERROR;
}
+ // ------------------------------------------------------------------------------------
+ // Full restore interfaces
+
+ /**
+ * Ask the transport to provide data for the "current" package being restored. This
+ * is the package that was just reported by {@link #nextRestorePackage()} as having
+ * {@link RestoreDescription#TYPE_FULL_STREAM} data.
+ *
+ * The transport writes some data to the socket supplied to this call, and returns
+ * the number of bytes written. The system will then read that many bytes and
+ * stream them to the application's agent for restore, then will call this method again
+ * to receive the next chunk of the archive. This sequence will be repeated until the
+ * transport returns zero indicating that all of the package's data has been delivered
+ * (or returns a negative value indicating some sort of hard error condition at the
+ * transport level).
+ *
+ * <p>After this method returns zero, the system will then call
+ * {@link #getNextFullRestorePackage()} to begin the restore process for the next
+ * application, and the sequence begins again.
+ *
+ * <p>The transport should always close this socket when returning from this method.
+ * Do not cache this socket across multiple calls or you may leak file descriptors.
+ *
+ * @param socket The file descriptor that the transport will use for delivering the
+ * streamed archive. The transport must close this socket in all cases when returning
+ * from this method.
+ * @return 0 when no more data for the current package is available. A positive value
+ * indicates the presence of that many bytes to be delivered to the app. Any negative
+ * return value is treated as equivalent to {@link BackupTransport#TRANSPORT_ERROR},
+ * indicating a fatal error condition that precludes further restore operations
+ * on the current dataset.
+ */
+ public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
+ return 0;
+ }
+
+ /**
+ * If the OS encounters an error while processing {@link RestoreDescription#TYPE_FULL_STREAM}
+ * data for restore, it will invoke this method to tell the transport that it should
+ * abandon the data download for the current package. The OS will then either call
+ * {@link #nextRestorePackage()} again to move on to restoring the next package in the
+ * set being iterated over, or will call {@link #finishRestore()} to shut down the restore
+ * operation.
+ *
+ * @return {@link #TRANSPORT_OK} if the transport was successful in shutting down the
+ * current stream cleanly, or {@link #TRANSPORT_ERROR} to indicate a serious
+ * transport-level failure. If the transport reports an error here, the entire restore
+ * operation will immediately be finished with no further attempts to restore app data.
+ */
+ public int abortFullRestore() {
+ return BackupTransport.TRANSPORT_OK;
+ }
+
/**
* Bridge between the actual IBackupTransport implementation and the stable API. If the
* binder interface needs to change, we use this layer to translate so that we can
@@ -398,7 +467,7 @@
}
@Override
- public String nextRestorePackage() throws RemoteException {
+ public RestoreDescription nextRestorePackage() throws RemoteException {
return BackupTransport.this.nextRestorePackage();
}
@@ -411,5 +480,30 @@
public void finishRestore() throws RemoteException {
BackupTransport.this.finishRestore();
}
+
+ @Override
+ public long requestFullBackupTime() throws RemoteException {
+ return BackupTransport.this.requestFullBackupTime();
+ }
+
+ @Override
+ public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) throws RemoteException {
+ return BackupTransport.this.performFullBackup(targetPackage, socket);
+ }
+
+ @Override
+ public int sendBackupData(int numBytes) throws RemoteException {
+ return BackupTransport.this.sendBackupData(numBytes);
+ }
+
+ @Override
+ public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
+ return BackupTransport.this.getNextFullRestoreDataChunk(socket);
+ }
+
+ @Override
+ public int abortFullRestore() {
+ return BackupTransport.this.abortFullRestore();
+ }
}
}
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index c629a2e..72bc4f0 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -168,7 +168,15 @@
*/
void fullBackup(in ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,
boolean includeShared, boolean doWidgets, boolean allApps, boolean allIncludesSystem,
- in String[] packageNames);
+ boolean doCompress, in String[] packageNames);
+
+ /**
+ * Perform a full-dataset backup of the given applications via the currently active
+ * transport.
+ *
+ * @param packageNames The package names of the apps whose data are to be backed up.
+ */
+ void fullTransportBackup(in String[] packageNames);
/**
* Restore device content from the data stream passed through the given socket. The
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/app/backup/RestoreDescription.aidl
similarity index 90%
copy from core/java/android/app/task/Task.aidl
copy to core/java/android/app/backup/RestoreDescription.aidl
index 1f25439..9cbea78 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/core/java/android/app/backup/RestoreDescription.aidl
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-package android.app.task;
+package android.app.backup;
-parcelable Task;
-
\ No newline at end of file
+parcelable RestoreDescription;
diff --git a/core/java/android/app/backup/RestoreDescription.java b/core/java/android/app/backup/RestoreDescription.java
new file mode 100644
index 0000000..0fb4355
--- /dev/null
+++ b/core/java/android/app/backup/RestoreDescription.java
@@ -0,0 +1,101 @@
+/*
+ * 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.app.backup;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Description of the available restore data for a given package. Returned by a
+ * BackupTransport in response to a request about the next available restorable
+ * package.
+ *
+ * @see BackupTransport#nextRestorePackage()
+ *
+ * @hide
+ */
+public class RestoreDescription implements Parcelable {
+ private final String mPackageName;
+ private final int mDataType;
+
+ private static final String NO_MORE_PACKAGES_SENTINEL = "";
+
+ /**
+ * Return this constant RestoreDescription from BackupTransport.nextRestorePackage()
+ * to indicate that no more package data is available in the current restore operation.
+ */
+ public static final RestoreDescription NO_MORE_PACKAGES =
+ new RestoreDescription(NO_MORE_PACKAGES_SENTINEL, 0);
+
+ // ---------------------------------------
+ // Data type identifiers
+
+ /** This package's restore data is an original-style key/value dataset */
+ public static final int TYPE_KEY_VALUE = 1;
+
+ /** This package's restore data is a tarball-type full data stream */
+ public static final int TYPE_FULL_STREAM = 2;
+
+ // ---------------------------------------
+ // API
+
+ public RestoreDescription(String packageName, int dataType) {
+ mPackageName = packageName;
+ mDataType = dataType;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public int getDataType() {
+ return mDataType;
+ }
+
+ // ---------------------------------------
+ // Parcelable implementation - not used by transport
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mPackageName);
+ out.writeInt(mDataType);
+ }
+
+ public static final Parcelable.Creator<RestoreDescription> CREATOR
+ = new Parcelable.Creator<RestoreDescription>() {
+ public RestoreDescription createFromParcel(Parcel in) {
+ final RestoreDescription unparceled = new RestoreDescription(in);
+ return (NO_MORE_PACKAGES_SENTINEL.equals(unparceled.mPackageName))
+ ? NO_MORE_PACKAGES
+ : unparceled;
+ }
+
+ public RestoreDescription[] newArray(int size) {
+ return new RestoreDescription[size];
+ }
+ };
+
+ private RestoreDescription(Parcel in) {
+ mPackageName = in.readString();
+ mDataType = in.readInt();
+ }
+}
diff --git a/core/java/android/app/job/IJobCallback.aidl b/core/java/android/app/job/IJobCallback.aidl
new file mode 100644
index 0000000..2d3948f
--- /dev/null
+++ b/core/java/android/app/job/IJobCallback.aidl
@@ -0,0 +1,53 @@
+/**
+ * Copyright 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.app.job;
+
+/**
+ * The server side of the JobScheduler IPC protocols. The app-side implementation
+ * invokes on this interface to indicate completion of the (asynchronous) instructions
+ * issued by the server.
+ *
+ * In all cases, the 'who' parameter is the caller's service binder, used to track
+ * which Job Service instance is reporting.
+ *
+ * {@hide}
+ */
+interface IJobCallback {
+ /**
+ * Immediate callback to the system after sending a start signal, used to quickly detect ANR.
+ *
+ * @param jobId Unique integer used to identify this job.
+ * @param ongoing True to indicate that the client is processing the job. False if the job is
+ * complete
+ */
+ void acknowledgeStartMessage(int jobId, boolean ongoing);
+ /**
+ * Immediate callback to the system after sending a stop signal, used to quickly detect ANR.
+ *
+ * @param jobId Unique integer used to identify this job.
+ * @param reschedule Whether or not to reschedule this job.
+ */
+ void acknowledgeStopMessage(int jobId, boolean reschedule);
+ /*
+ * Tell the job manager that the client is done with its execution, so that it can go on to
+ * the next one and stop attributing wakelock time to us etc.
+ *
+ * @param jobId Unique integer used to identify this job.
+ * @param reschedule Whether or not to reschedule this job.
+ */
+ void jobFinished(int jobId, boolean reschedule);
+}
diff --git a/core/java/android/app/task/ITaskManager.aidl b/core/java/android/app/job/IJobScheduler.aidl
similarity index 71%
rename from core/java/android/app/task/ITaskManager.aidl
rename to core/java/android/app/job/IJobScheduler.aidl
index b56c78a..f1258ae 100644
--- a/core/java/android/app/task/ITaskManager.aidl
+++ b/core/java/android/app/job/IJobScheduler.aidl
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package android.app.task;
+package android.app.job;
-import android.app.task.Task;
+import android.app.job.JobInfo;
/**
- * IPC interface that supports the app-facing {@link #TaskManager} api.
+ * IPC interface that supports the app-facing {@link #JobScheduler} api.
* {@hide}
*/
-interface ITaskManager {
- int schedule(in Task task);
- void cancel(int taskId);
+interface IJobScheduler {
+ int schedule(in JobInfo job);
+ void cancel(int jobId);
void cancelAll();
- List<Task> getAllPendingTasks();
+ List<JobInfo> getAllPendingJobs();
}
diff --git a/core/java/android/app/task/ITaskService.aidl b/core/java/android/app/job/IJobService.aidl
similarity index 62%
rename from core/java/android/app/task/ITaskService.aidl
rename to core/java/android/app/job/IJobService.aidl
index 87b0191..63f8b81 100644
--- a/core/java/android/app/task/ITaskService.aidl
+++ b/core/java/android/app/job/IJobService.aidl
@@ -14,22 +14,19 @@
* limitations under the License.
*/
-package android.app.task;
+package android.app.job;
-import android.app.task.ITaskCallback;
-import android.app.task.TaskParams;
-
-import android.os.Bundle;
+import android.app.job.JobParameters;
/**
* Interface that the framework uses to communicate with application code that implements a
- * TaskService. End user code does not implement this interface directly; instead, the app's
- * service implementation will extend android.app.task.TaskService.
+ * JobService. End user code does not implement this interface directly; instead, the app's
+ * service implementation will extend android.app.job.JobService.
* {@hide}
*/
-oneway interface ITaskService {
- /** Begin execution of application's task. */
- void startTask(in TaskParams taskParams);
+oneway interface IJobService {
+ /** Begin execution of application's job. */
+ void startJob(in JobParameters jobParams);
/** Stop execution of application's task. */
- void stopTask(in TaskParams taskParams);
+ void stopJob(in JobParameters jobParams);
}
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/app/job/JobInfo.aidl
similarity index 92%
rename from core/java/android/app/task/Task.aidl
rename to core/java/android/app/job/JobInfo.aidl
index 1f25439..7b198a8 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/core/java/android/app/job/JobInfo.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-package android.app.task;
+package android.app.job;
-parcelable Task;
-
\ No newline at end of file
+parcelable JobInfo;
diff --git a/core/java/android/app/task/Task.java b/core/java/android/app/job/JobInfo.java
similarity index 72%
rename from core/java/android/app/task/Task.java
rename to core/java/android/app/job/JobInfo.java
index 87d57fb4..a22e4cd 100644
--- a/core/java/android/app/task/Task.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package android.app.task;
+package android.app.job;
import android.content.ComponentName;
import android.os.Bundle;
@@ -23,22 +23,22 @@
import android.os.PersistableBundle;
/**
- * Container of data passed to the {@link android.app.task.TaskManager} fully encapsulating the
+ * Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
* parameters required to schedule work against the calling application. These are constructed
- * using the {@link Task.Builder}.
+ * using the {@link JobInfo.Builder}.
*/
-public class Task implements Parcelable {
+public class JobInfo implements Parcelable {
public interface NetworkType {
/** Default. */
public final int NONE = 0;
- /** This task requires network connectivity. */
+ /** This job requires network connectivity. */
public final int ANY = 1;
- /** This task requires network connectivity that is unmetered. */
+ /** This job requires network connectivity that is unmetered. */
public final int UNMETERED = 2;
}
/**
- * Amount of backoff a task has initially by default, in milliseconds.
+ * Amount of backoff a job has initially by default, in milliseconds.
* @hide.
*/
public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 5000L;
@@ -48,6 +48,11 @@
* @hide
*/
public static final int DEFAULT_BACKOFF_POLICY = BackoffPolicy.EXPONENTIAL;
+ /**
+ * Maximum backoff we allow for a job, in milliseconds.
+ * @hide
+ */
+ public static final long MAX_BACKOFF_DELAY_MILLIS = 24 * 60 * 60 * 1000; // 24 hours.
/**
* Linear: retry_time(failure_time, t) = failure_time + initial_retry_delay * t, t >= 1
@@ -58,7 +63,7 @@
public final int EXPONENTIAL = 1;
}
- private final int taskId;
+ private final int jobId;
// TODO: Change this to use PersistableBundle when that lands in master.
private final PersistableBundle extras;
private final ComponentName service;
@@ -75,10 +80,10 @@
private final int backoffPolicy;
/**
- * Unique task id associated with this class. This is assigned to your task by the scheduler.
+ * Unique job id associated with this class. This is assigned to your job by the scheduler.
*/
public int getId() {
- return taskId;
+ return jobId;
}
/**
@@ -89,43 +94,43 @@
}
/**
- * Name of the service endpoint that will be called back into by the TaskManager.
+ * Name of the service endpoint that will be called back into by the JobScheduler.
*/
public ComponentName getService() {
return service;
}
/**
- * Whether this task needs the device to be plugged in.
+ * Whether this job needs the device to be plugged in.
*/
public boolean isRequireCharging() {
return requireCharging;
}
/**
- * Whether this task needs the device to be in an Idle maintenance window.
+ * Whether this job needs the device to be in an Idle maintenance window.
*/
public boolean isRequireDeviceIdle() {
return requireDeviceIdle;
}
/**
- * See {@link android.app.task.Task.NetworkType} for a description of this value.
+ * See {@link android.app.job.JobInfo.NetworkType} for a description of this value.
*/
public int getNetworkCapabilities() {
return networkCapabilities;
}
/**
- * Set for a task that does not recur periodically, to specify a delay after which the task
- * will be eligible for execution. This value is not set if the task recurs periodically.
+ * Set for a job that does not recur periodically, to specify a delay after which the job
+ * will be eligible for execution. This value is not set if the job recurs periodically.
*/
public long getMinLatencyMillis() {
return minLatencyMillis;
}
/**
- * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the task recurs
+ * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the job recurs
* periodically.
*/
public long getMaxExecutionDelayMillis() {
@@ -133,23 +138,23 @@
}
/**
- * Track whether this task will repeat with a given period.
+ * Track whether this job will repeat with a given period.
*/
public boolean isPeriodic() {
return isPeriodic;
}
/**
- * Set to the interval between occurrences of this task. This value is <b>not</b> set if the
- * task does not recur periodically.
+ * Set to the interval between occurrences of this job. This value is <b>not</b> set if the
+ * job does not recur periodically.
*/
public long getIntervalMillis() {
return intervalMillis;
}
/**
- * The amount of time the TaskManager will wait before rescheduling a failed task. This value
- * will be increased depending on the backoff policy specified at task creation time. Defaults
+ * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
+ * will be increased depending on the backoff policy specified at job creation time. Defaults
* to 5 seconds.
*/
public long getInitialBackoffMillis() {
@@ -157,7 +162,7 @@
}
/**
- * See {@link android.app.task.Task.BackoffPolicy} for an explanation of the values this field
+ * See {@link android.app.job.JobInfo.BackoffPolicy} for an explanation of the values this field
* can take. This defaults to exponential.
*/
public int getBackoffPolicy() {
@@ -182,10 +187,10 @@
return hasLateConstraint;
}
- private Task(Parcel in) {
- taskId = in.readInt();
+ private JobInfo(Parcel in) {
+ jobId = in.readInt();
extras = in.readPersistableBundle();
- service = ComponentName.readFromParcel(in);
+ service = in.readParcelable(null);
requireCharging = in.readInt() == 1;
requireDeviceIdle = in.readInt() == 1;
networkCapabilities = in.readInt();
@@ -199,10 +204,10 @@
hasLateConstraint = in.readInt() == 1;
}
- private Task(Task.Builder b) {
- taskId = b.mTaskId;
- extras = new PersistableBundle(b.mExtras);
- service = b.mTaskService;
+ private JobInfo(JobInfo.Builder b) {
+ jobId = b.mJobId;
+ extras = b.mExtras;
+ service = b.mJobService;
requireCharging = b.mRequiresCharging;
requireDeviceIdle = b.mRequiresDeviceIdle;
networkCapabilities = b.mNetworkCapabilities;
@@ -223,9 +228,9 @@
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeInt(taskId);
+ out.writeInt(jobId);
out.writePersistableBundle(extras);
- ComponentName.writeToParcel(service, out);
+ out.writeParcelable(service, flags);
out.writeInt(requireCharging ? 1 : 0);
out.writeInt(requireDeviceIdle ? 1 : 0);
out.writeInt(networkCapabilities);
@@ -239,23 +244,23 @@
out.writeInt(hasLateConstraint ? 1 : 0);
}
- public static final Creator<Task> CREATOR = new Creator<Task>() {
+ public static final Creator<JobInfo> CREATOR = new Creator<JobInfo>() {
@Override
- public Task createFromParcel(Parcel in) {
- return new Task(in);
+ public JobInfo createFromParcel(Parcel in) {
+ return new JobInfo(in);
}
@Override
- public Task[] newArray(int size) {
- return new Task[size];
+ public JobInfo[] newArray(int size) {
+ return new JobInfo[size];
}
};
- /** Builder class for constructing {@link Task} objects. */
+ /** Builder class for constructing {@link JobInfo} objects. */
public static final class Builder {
- private int mTaskId;
+ private int mJobId;
private PersistableBundle mExtras = PersistableBundle.EMPTY;
- private ComponentName mTaskService;
+ private ComponentName mJobService;
// Requirements.
private boolean mRequiresCharging;
private boolean mRequiresDeviceIdle;
@@ -275,15 +280,15 @@
private boolean mBackoffPolicySet = false;
/**
- * @param taskId Application-provided id for this task. Subsequent calls to cancel, or
- * tasks created with the same taskId, will update the pre-existing task with
+ * @param jobId Application-provided id for this job. Subsequent calls to cancel, or
+ * jobs created with the same jobId, will update the pre-existing job with
* the same id.
- * @param taskService The endpoint that you implement that will receive the callback from the
- * TaskManager.
+ * @param jobService The endpoint that you implement that will receive the callback from the
+ * JobScheduler.
*/
- public Builder(int taskId, ComponentName taskService) {
- mTaskService = taskService;
- mTaskId = taskId;
+ public Builder(int jobId, ComponentName jobService) {
+ mJobService = jobService;
+ mJobId = jobId;
}
/**
@@ -297,10 +302,10 @@
/**
* Set some description of the kind of network capabilities you would like to have. This
- * will be a parameter defined in {@link android.app.task.Task.NetworkType}.
+ * will be a parameter defined in {@link android.app.job.JobInfo.NetworkType}.
* Not calling this function means the network is not necessary.
* Bear in mind that calling this function defines network as a strict requirement for your
- * task if the network requested is not available your task will never run. See
+ * job if the network requested is not available your job will never run. See
* {@link #setOverrideDeadline(long)} to change this behaviour.
*/
public Builder setRequiredNetworkCapabilities(int networkCapabilities) {
@@ -308,10 +313,10 @@
return this;
}
- /*
- * Specify that to run this task, the device needs to be plugged in. This defaults to
+ /**
+ * Specify that to run this job, the device needs to be plugged in. This defaults to
* false.
- * @param requireCharging Whether or not the device is plugged in.
+ * @param requiresCharging Whether or not the device is plugged in.
*/
public Builder setRequiresCharging(boolean requiresCharging) {
mRequiresCharging = requiresCharging;
@@ -319,11 +324,11 @@
}
/**
- * Specify that to run, the task needs the device to be in idle mode. This defaults to
+ * Specify that to run, the job needs the device to be in idle mode. This defaults to
* false.
* <p>Idle mode is a loose definition provided by the system, which means that the device
* is not in use, and has not been in use for some time. As such, it is a good time to
- * perform resource heavy tasks. Bear in mind that battery usage will still be attributed
+ * perform resource heavy jobs. Bear in mind that battery usage will still be attributed
* to your application, and surfaced to the user in battery stats.</p>
* @param requiresDeviceIdle Whether or not the device need be within an idle maintenance
* window.
@@ -334,17 +339,17 @@
}
/**
- * Specify that this task should recur with the provided interval, not more than once per
- * period. You have no control over when within this interval this task will be executed,
+ * Specify that this job should recur with the provided interval, not more than once per
+ * period. You have no control over when within this interval this job will be executed,
* only the guarantee that it will be executed at most once within this interval.
- * A periodic task will be repeated until the phone is turned off, however it will only be
+ * A periodic job will be repeated until the phone is turned off, however it will only be
* persisted beyond boot if the client app has declared the
* {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission. You can schedule
- * periodic tasks without this permission, they simply will cease to exist after the phone
+ * periodic jobs without this permission, they simply will cease to exist after the phone
* restarts.
* Setting this function on the builder with {@link #setMinimumLatency(long)} or
* {@link #setOverrideDeadline(long)} will result in an error.
- * @param intervalMillis Millisecond interval for which this task will repeat.
+ * @param intervalMillis Millisecond interval for which this job will repeat.
*/
public Builder setPeriodic(long intervalMillis) {
mIsPeriodic = true;
@@ -354,11 +359,11 @@
}
/**
- * Specify that this task should be delayed by the provided amount of time.
- * Because it doesn't make sense setting this property on a periodic task, doing so will
+ * Specify that this job should be delayed by the provided amount of time.
+ * Because it doesn't make sense setting this property on a periodic job, doing so will
* throw an {@link java.lang.IllegalArgumentException} when
- * {@link android.app.task.Task.Builder#build()} is called.
- * @param minLatencyMillis Milliseconds before which this task will not be considered for
+ * {@link android.app.job.JobInfo.Builder#build()} is called.
+ * @param minLatencyMillis Milliseconds before which this job will not be considered for
* execution.
*/
public Builder setMinimumLatency(long minLatencyMillis) {
@@ -368,11 +373,11 @@
}
/**
- * Set deadline which is the maximum scheduling latency. The task will be run by this
+ * Set deadline which is the maximum scheduling latency. The job will be run by this
* deadline even if other requirements are not met. Because it doesn't make sense setting
- * this property on a periodic task, doing so will throw an
+ * this property on a periodic job, doing so will throw an
* {@link java.lang.IllegalArgumentException} when
- * {@link android.app.task.Task.Builder#build()} is called.
+ * {@link android.app.job.JobInfo.Builder#build()} is called.
*/
public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
mMaxExecutionDelayMillis = maxExecutionDelayMillis;
@@ -384,13 +389,13 @@
* Set up the back-off/retry policy.
* This defaults to some respectable values: {5 seconds, Exponential}. We cap back-off at
* 1hr.
- * Note that trying to set a backoff criteria for a task with
+ * Note that trying to set a backoff criteria for a job with
* {@link #setRequiresDeviceIdle(boolean)} will throw an exception when you call build().
- * This is because back-off typically does not make sense for these types of tasks. See
- * {@link android.app.task.TaskService#taskFinished(android.app.task.TaskParams, boolean)}
- * for more description of the return value for the case of a task executing while in idle
+ * This is because back-off typically does not make sense for these types of jobs. See
+ * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
+ * for more description of the return value for the case of a job executing while in idle
* mode.
- * @param initialBackoffMillis Millisecond time interval to wait initially when task has
+ * @param initialBackoffMillis Millisecond time interval to wait initially when job has
* failed.
* @param backoffPolicy is one of {@link BackoffPolicy}
*/
@@ -402,25 +407,25 @@
}
/**
- * @return The task object to hand to the TaskManager. This object is immutable.
+ * @return The job object to hand to the JobScheduler. This object is immutable.
*/
- public Task build() {
+ public JobInfo build() {
mExtras = new PersistableBundle(mExtras); // Make our own copy.
- // Check that a deadline was not set on a periodic task.
+ // Check that a deadline was not set on a periodic job.
if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
throw new IllegalArgumentException("Can't call setOverrideDeadline() on a " +
- "periodic task.");
+ "periodic job.");
}
if (mIsPeriodic && (mMinLatencyMillis != 0L)) {
throw new IllegalArgumentException("Can't call setMinimumLatency() on a " +
- "periodic task");
+ "periodic job");
}
if (mBackoffPolicySet && mRequiresDeviceIdle) {
- throw new IllegalArgumentException("An idle mode task will not respect any" +
+ throw new IllegalArgumentException("An idle mode job will not respect any" +
" back-off policy, so calling setBackoffCriteria with" +
" setRequiresDeviceIdle is an error.");
}
- return new Task(this);
+ return new JobInfo(this);
}
}
diff --git a/core/java/android/app/task/TaskParams.aidl b/core/java/android/app/job/JobParameters.aidl
similarity index 91%
rename from core/java/android/app/task/TaskParams.aidl
rename to core/java/android/app/job/JobParameters.aidl
index 9b25855..e7551b9 100644
--- a/core/java/android/app/task/TaskParams.aidl
+++ b/core/java/android/app/job/JobParameters.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.app.task;
+package android.app.job;
-parcelable TaskParams;
\ No newline at end of file
+parcelable JobParameters;
diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java
new file mode 100644
index 0000000..724856a
--- /dev/null
+++ b/core/java/android/app/job/JobParameters.java
@@ -0,0 +1,93 @@
+/*
+ * 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.app.job;
+
+import android.app.job.IJobCallback;
+import android.app.job.IJobCallback.Stub;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PersistableBundle;
+
+/**
+ * Contains the parameters used to configure/identify your job. You do not create this object
+ * yourself, instead it is handed in to your application by the System.
+ */
+public class JobParameters implements Parcelable {
+
+ private final int jobId;
+ private final PersistableBundle extras;
+ private final IBinder callback;
+
+ /** @hide */
+ public JobParameters(int jobId, PersistableBundle extras, IBinder callback) {
+ this.jobId = jobId;
+ this.extras = extras;
+ this.callback = callback;
+ }
+
+ /**
+ * @return The unique id of this job, specified at creation time.
+ */
+ public int getJobId() {
+ return jobId;
+ }
+
+ /**
+ * @return The extras you passed in when constructing this job with
+ * {@link android.app.job.JobInfo.Builder#setExtras(android.os.PersistableBundle)}. This will
+ * never be null. If you did not set any extras this will be an empty bundle.
+ */
+ public PersistableBundle getExtras() {
+ return extras;
+ }
+
+ /** @hide */
+ public IJobCallback getCallback() {
+ return IJobCallback.Stub.asInterface(callback);
+ }
+
+ private JobParameters(Parcel in) {
+ jobId = in.readInt();
+ extras = in.readPersistableBundle();
+ callback = in.readStrongBinder();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(jobId);
+ dest.writePersistableBundle(extras);
+ dest.writeStrongBinder(callback);
+ }
+
+ public static final Creator<JobParameters> CREATOR = new Creator<JobParameters>() {
+ @Override
+ public JobParameters createFromParcel(Parcel in) {
+ return new JobParameters(in);
+ }
+
+ @Override
+ public JobParameters[] newArray(int size) {
+ return new JobParameters[size];
+ }
+ };
+}
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
new file mode 100644
index 0000000..7fe192c
--- /dev/null
+++ b/core/java/android/app/job/JobScheduler.java
@@ -0,0 +1,72 @@
+/*
+ * 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.app.job;
+
+import java.util.List;
+
+import android.content.Context;
+
+/**
+ * Class for scheduling various types of jobs with the scheduling framework on the device.
+ *
+ * <p>You do not
+ * instantiate this class directly; instead, retrieve it through
+ * {@link android.content.Context#getSystemService
+ * Context.getSystemService(Context.JOB_SCHEDULER_SERVICE)}.
+ */
+public abstract class JobScheduler {
+ /**
+ * Returned from {@link #schedule(JobInfo)} when an invalid parameter was supplied. This can occur
+ * if the run-time for your job is too short, or perhaps the system can't resolve the
+ * requisite {@link JobService} in your package.
+ */
+ public static final int RESULT_FAILURE = 0;
+ /**
+ * Returned from {@link #schedule(JobInfo)} if this application has made too many requests for
+ * work over too short a time.
+ */
+ // TODO: Determine if this is necessary.
+ public static final int RESULT_SUCCESS = 1;
+
+ /**
+ * @param job The job you wish scheduled. See
+ * {@link android.app.job.JobInfo.Builder JobInfo.Builder} for more detail on the sorts of jobs
+ * you can schedule.
+ * @return If >0, this int returns the jobId of the successfully scheduled job.
+ * Otherwise you have to compare the return value to the error codes defined in this class.
+ */
+ public abstract int schedule(JobInfo job);
+
+ /**
+ * Cancel a job that is pending in the JobScheduler.
+ * @param jobId unique identifier for this job. Obtain this value from the jobs returned by
+ * {@link #getAllPendingJobs()}.
+ * @return
+ */
+ public abstract void cancel(int jobId);
+
+ /**
+ * Cancel all jobs that have been registered with the JobScheduler by this package.
+ */
+ public abstract void cancelAll();
+
+ /**
+ * @return a list of all the jobs registered by this package that have not yet been executed.
+ */
+ public abstract List<JobInfo> getAllPendingJobs();
+
+}
diff --git a/core/java/android/app/job/JobService.java b/core/java/android/app/job/JobService.java
new file mode 100644
index 0000000..eea0268
--- /dev/null
+++ b/core/java/android/app/job/JobService.java
@@ -0,0 +1,260 @@
+/*
+ * 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.app.job;
+
+import android.app.Service;
+import android.app.job.IJobCallback;
+import android.app.job.IJobService;
+import android.app.job.IJobService.Stub;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * <p>Entry point for the callback from the {@link android.app.job.JobScheduler}.</p>
+ * <p>This is the base class that handles asynchronous requests that were previously scheduled. You
+ * are responsible for overriding {@link JobService#onStartJob(JobParameters)}, which is where
+ * you will implement your job logic.</p>
+ * <p>This service executes each incoming job on a {@link android.os.Handler} running on your
+ * application's main thread. This means that you <b>must</b> offload your execution logic to
+ * another thread/handler/{@link android.os.AsyncTask} of your choosing. Not doing so will result
+ * in blocking any future callbacks from the JobManager - specifically
+ * {@link #onStopJob(android.app.job.JobParameters)}, which is meant to inform you that the
+ * scheduling requirements are no longer being met.</p>
+ */
+public abstract class JobService extends Service {
+ private static final String TAG = "JobService";
+
+ /**
+ * Job services must be protected with this permission:
+ *
+ * <pre class="prettyprint">
+ * <service android:name="MyJobService"
+ * android:permission="android.permission.BIND_JOB_SERVICE" >
+ * ...
+ * </service>
+ * </pre>
+ *
+ * <p>If a job service is declared in the manifest but not protected with this
+ * permission, that service will be ignored by the OS.
+ */
+ public static final String PERMISSION_BIND =
+ "android.permission.BIND_JOB_SERVICE";
+
+ /**
+ * Identifier for a message that will result in a call to
+ * {@link #onStartJob(android.app.job.JobParameters)}.
+ */
+ private final int MSG_EXECUTE_JOB = 0;
+ /**
+ * Message that will result in a call to {@link #onStopJob(android.app.job.JobParameters)}.
+ */
+ private final int MSG_STOP_JOB = 1;
+ /**
+ * Message that the client has completed execution of this job.
+ */
+ private final int MSG_JOB_FINISHED = 2;
+
+ /** Lock object for {@link #mHandler}. */
+ private final Object mHandlerLock = new Object();
+
+ /**
+ * Handler we post jobs to. Responsible for calling into the client logic, and handling the
+ * callback to the system.
+ */
+ @GuardedBy("mHandlerLock")
+ JobHandler mHandler;
+
+ /** Binder for this service. */
+ IJobService mBinder = new IJobService.Stub() {
+ @Override
+ public void startJob(JobParameters jobParams) {
+ ensureHandler();
+ Message m = Message.obtain(mHandler, MSG_EXECUTE_JOB, jobParams);
+ m.sendToTarget();
+ }
+ @Override
+ public void stopJob(JobParameters jobParams) {
+ ensureHandler();
+ Message m = Message.obtain(mHandler, MSG_STOP_JOB, jobParams);
+ m.sendToTarget();
+ }
+ };
+
+ /** @hide */
+ void ensureHandler() {
+ synchronized (mHandlerLock) {
+ if (mHandler == null) {
+ mHandler = new JobHandler(getMainLooper());
+ }
+ }
+ }
+
+ /**
+ * Runs on application's main thread - callbacks are meant to offboard work to some other
+ * (app-specified) mechanism.
+ * @hide
+ */
+ class JobHandler extends Handler {
+ JobHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ final JobParameters params = (JobParameters) msg.obj;
+ switch (msg.what) {
+ case MSG_EXECUTE_JOB:
+ try {
+ boolean workOngoing = JobService.this.onStartJob(params);
+ ackStartMessage(params, workOngoing);
+ } catch (Exception e) {
+ Log.e(TAG, "Error while executing job: " + params.getJobId());
+ throw new RuntimeException(e);
+ }
+ break;
+ case MSG_STOP_JOB:
+ try {
+ boolean ret = JobService.this.onStopJob(params);
+ ackStopMessage(params, ret);
+ } catch (Exception e) {
+ Log.e(TAG, "Application unable to handle onStopJob.", e);
+ throw new RuntimeException(e);
+ }
+ break;
+ case MSG_JOB_FINISHED:
+ final boolean needsReschedule = (msg.arg2 == 1);
+ IJobCallback callback = params.getCallback();
+ if (callback != null) {
+ try {
+ callback.jobFinished(params.getJobId(), needsReschedule);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error reporting job finish to system: binder has gone" +
+ "away.");
+ }
+ } else {
+ Log.e(TAG, "finishJob() called for a nonexistent job id.");
+ }
+ break;
+ default:
+ Log.e(TAG, "Unrecognised message received.");
+ break;
+ }
+ }
+
+ private void ackStartMessage(JobParameters params, boolean workOngoing) {
+ final IJobCallback callback = params.getCallback();
+ final int jobId = params.getJobId();
+ if (callback != null) {
+ try {
+ callback.acknowledgeStartMessage(jobId, workOngoing);
+ } catch(RemoteException e) {
+ Log.e(TAG, "System unreachable for starting job.");
+ }
+ } else {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Attempting to ack a job that has already been processed.");
+ }
+ }
+ }
+
+ private void ackStopMessage(JobParameters params, boolean reschedule) {
+ final IJobCallback callback = params.getCallback();
+ final int jobId = params.getJobId();
+ if (callback != null) {
+ try {
+ callback.acknowledgeStopMessage(jobId, reschedule);
+ } catch(RemoteException e) {
+ Log.e(TAG, "System unreachable for stopping job.");
+ }
+ } else {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Attempting to ack a job that has already been processed.");
+ }
+ }
+ }
+ }
+
+ /** @hide */
+ public final IBinder onBind(Intent intent) {
+ return mBinder.asBinder();
+ }
+
+ /**
+ * Override this method with the callback logic for your job. Any such logic needs to be
+ * performed on a separate thread, as this function is executed on your application's main
+ * thread.
+ *
+ * @param params Parameters specifying info about this job, including the extras bundle you
+ * optionally provided at job-creation time.
+ * @return True if your service needs to process the work (on a separate thread). False if
+ * there's no more work to be done for this job.
+ */
+ public abstract boolean onStartJob(JobParameters params);
+
+ /**
+ * This method is called if the system has determined that you must stop execution of your job
+ * even before you've had a chance to call {@link #jobFinished(JobParameters, boolean)}.
+ *
+ * <p>This will happen if the requirements specified at schedule time are no longer met. For
+ * example you may have requested WiFi with
+ * {@link android.app.job.JobInfo.Builder#setRequiredNetworkCapabilities(int)}, yet while your
+ * job was executing the user toggled WiFi. Another example is if you had specified
+ * {@link android.app.job.JobInfo.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
+ * idle maintenance window. You are solely responsible for the behaviour of your application
+ * upon receipt of this message; your app will likely start to misbehave if you ignore it. One
+ * immediate repercussion is that the system will cease holding a wakelock for you.</p>
+ *
+ * @param params Parameters specifying info about this job.
+ * @return True to indicate to the JobManager whether you'd like to reschedule this job based
+ * on the retry criteria provided at job creation-time. False to drop the job. Regardless of
+ * the value returned, your job must stop executing.
+ */
+ public abstract boolean onStopJob(JobParameters params);
+
+ /**
+ * Callback to inform the JobManager you've finished executing. This can be called from any
+ * thread, as it will ultimately be run on your application's main thread. When the system
+ * receives this message it will release the wakelock being held.
+ * <p>
+ * You can specify post-execution behaviour to the scheduler here with
+ * <code>needsReschedule </code>. This will apply a back-off timer to your job based on
+ * the default, or what was set with
+ * {@link android.app.job.JobInfo.Builder#setBackoffCriteria(long, int)}. The original
+ * requirements are always honoured even for a backed-off job. Note that a job running in
+ * idle mode will not be backed-off. Instead what will happen is the job will be re-added
+ * to the queue and re-executed within a future idle maintenance window.
+ * </p>
+ *
+ * @param params Parameters specifying system-provided info about this job, this was given to
+ * your application in {@link #onStartJob(JobParameters)}.
+ * @param needsReschedule True if this job is complete, false if you want the JobManager to
+ * reschedule you.
+ */
+ public final void jobFinished(JobParameters params, boolean needsReschedule) {
+ ensureHandler();
+ Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params);
+ m.arg2 = needsReschedule ? 1 : 0;
+ m.sendToTarget();
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/app/maintenance/IIdleCallback.aidl b/core/java/android/app/maintenance/IIdleCallback.aidl
deleted file mode 100644
index 582dede..0000000
--- a/core/java/android/app/maintenance/IIdleCallback.aidl
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * Copyright 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.app.maintenance;
-
-import android.app.maintenance.IIdleService;
-
-/**
- * The server side of the idle maintenance IPC protocols. The app-side implementation
- * invokes on this interface to indicate completion of the (asynchronous) instructions
- * issued by the server.
- *
- * In all cases, the 'who' parameter is the caller's service binder, used to track
- * which idle service instance is reporting.
- *
- * {@hide}
- */
-interface IIdleCallback {
- /**
- * Acknowledge receipt and processing of the asynchronous "start idle work" incall.
- * 'result' is true if the app wants some time to perform ongoing background
- * idle-time work; or false if the app declares that it does not need any time
- * for such work.
- */
- void acknowledgeStart(int token, boolean result);
-
- /**
- * Acknowledge receipt and processing of the asynchronous "stop idle work" incall.
- */
- void acknowledgeStop(int token);
-
- /*
- * Tell the idle service manager that we're done with our idle maintenance, so that
- * it can go on to the next one and stop attributing wakelock time to us etc.
- *
- * @param opToken The identifier passed in the startIdleMaintenance() call that
- * indicated the beginning of this service's idle timeslice.
- */
- void idleFinished(int token);
-}
diff --git a/core/java/android/app/maintenance/IIdleService.aidl b/core/java/android/app/maintenance/IIdleService.aidl
deleted file mode 100644
index 54abccd..0000000
--- a/core/java/android/app/maintenance/IIdleService.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Copyright 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.app.maintenance;
-
-import android.app.maintenance.IIdleCallback;
-
-/**
- * Interface that the framework uses to communicate with application code
- * that implements an idle-time "maintenance" service. End user code does
- * not implement this interface directly; instead, the app's idle service
- * implementation will extend android.app.maintenance.IdleService.
- * {@hide}
- */
-oneway interface IIdleService {
- /**
- * Begin your idle-time work.
- */
- void startIdleMaintenance(IIdleCallback callbackBinder, int token);
- void stopIdleMaintenance(IIdleCallback callbackBinder, int token);
-}
diff --git a/core/java/android/app/maintenance/IdleService.java b/core/java/android/app/maintenance/IdleService.java
deleted file mode 100644
index 2331b81..0000000
--- a/core/java/android/app/maintenance/IdleService.java
+++ /dev/null
@@ -1,228 +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.app.maintenance;
-
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.app.Service;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.Log;
-import android.util.Slog;
-
-/**
- * Idle maintenance API. Full docs TBW (to be written).
- */
-public abstract class IdleService extends Service {
- private static final String TAG = "IdleService";
-
- static final int MSG_START = 1;
- static final int MSG_STOP = 2;
- static final int MSG_FINISH = 3;
-
- IdleHandler mHandler;
- IIdleCallback mCallbackBinder;
- int mToken;
- final Object mHandlerLock = new Object();
-
- void ensureHandler() {
- synchronized (mHandlerLock) {
- if (mHandler == null) {
- mHandler = new IdleHandler(getMainLooper());
- }
- }
- }
-
- /**
- * TBW: the idle service should supply an intent-filter handling this intent
- * <p>
- * <p class="note">The application must also protect the idle service with the
- * {@code "android.permission.BIND_IDLE_SERVICE"} permission to ensure that other
- * applications cannot maliciously bind to it. If an idle service's manifest
- * declaration does not require that permission, it will never be invoked.
- * </p>
- */
- @SdkConstant(SdkConstantType.SERVICE_ACTION)
- public static final String SERVICE_INTERFACE =
- "android.service.idle.IdleService";
-
- /**
- * Idle services must be protected with this permission:
- *
- * <pre class="prettyprint">
- * <service android:name="MyIdleService"
- * android:permission="android.permission.BIND_IDLE_SERVICE" >
- * ...
- * </service>
- * </pre>
- *
- * <p>If an idle service is declared in the manifest but not protected with this
- * permission, that service will be ignored by the OS.
- */
- public static final String PERMISSION_BIND =
- "android.permission.BIND_IDLE_SERVICE";
-
- // Trampoline: the callbacks are always run on the main thread
- IIdleService mBinder = new IIdleService.Stub() {
- @Override
- public void startIdleMaintenance(IIdleCallback callbackBinder, int token)
- throws RemoteException {
- ensureHandler();
- Message msg = mHandler.obtainMessage(MSG_START, token, 0, callbackBinder);
- mHandler.sendMessage(msg);
- }
-
- @Override
- public void stopIdleMaintenance(IIdleCallback callbackBinder, int token)
- throws RemoteException {
- ensureHandler();
- Message msg = mHandler.obtainMessage(MSG_STOP, token, 0, callbackBinder);
- mHandler.sendMessage(msg);
- }
- };
-
- /**
- * Your application may begin doing "idle" maintenance work in the background.
- * <p>
- * Your application may continue to run in the background until it receives a call
- * to {@link #onIdleStop()}, at which point you <i>must</i> cease doing work. The
- * OS will hold a wakelock on your application's behalf from the time this method is
- * called until after the following call to {@link #onIdleStop()} returns.
- * </p>
- * <p>
- * Returning {@code false} from this method indicates that you have no ongoing work
- * to do at present. The OS will respond by immediately calling {@link #onIdleStop()}
- * and returning your application to its normal stopped state. Returning {@code true}
- * indicates that the application is indeed performing ongoing work, so the OS will
- * let your application run in this state until it's no longer appropriate.
- * </p>
- * <p>
- * You will always receive a matching call to {@link #onIdleStop()} even if your
- * application returns {@code false} from this method.
- *
- * @return {@code true} to indicate that the application wishes to perform some ongoing
- * background work; {@code false} to indicate that it does not need to perform such
- * work at present.
- */
- public abstract boolean onIdleStart();
-
- /**
- * Your app's maintenance opportunity is over. Once the application returns from
- * this method, the wakelock held by the OS on its behalf will be released.
- */
- public abstract void onIdleStop();
-
- /**
- * Tell the OS that you have finished your idle work. Calling this more than once,
- * or calling it when you have not received an {@link #onIdleStart()} callback, is
- * an error.
- *
- * <p>It is safe to call {@link #finishIdle()} from any thread.
- */
- public final void finishIdle() {
- ensureHandler();
- mHandler.sendEmptyMessage(MSG_FINISH);
- }
-
- class IdleHandler extends Handler {
- IdleHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_START: {
- // Call the concrete onIdleStart(), reporting its return value back to
- // the OS. If onIdleStart() throws, report it as a 'false' return but
- // rethrow the exception at the offending app.
- boolean result = false;
- IIdleCallback callbackBinder = (IIdleCallback) msg.obj;
- mCallbackBinder = callbackBinder;
- final int token = mToken = msg.arg1;
- try {
- result = IdleService.this.onIdleStart();
- } catch (Exception e) {
- Log.e(TAG, "Unable to start idle workload", e);
- throw new RuntimeException(e);
- } finally {
- // don't bother if the service already called finishIdle()
- if (mCallbackBinder != null) {
- try {
- callbackBinder.acknowledgeStart(token, result);
- } catch (RemoteException re) {
- Log.e(TAG, "System unreachable to start idle workload");
- }
- }
- }
- break;
- }
-
- case MSG_STOP: {
- // Structured just like MSG_START for the stop-idle bookend call.
- IIdleCallback callbackBinder = (IIdleCallback) msg.obj;
- final int token = msg.arg1;
- try {
- IdleService.this.onIdleStop();
- } catch (Exception e) {
- Log.e(TAG, "Unable to stop idle workload", e);
- throw new RuntimeException(e);
- } finally {
- if (mCallbackBinder != null) {
- try {
- callbackBinder.acknowledgeStop(token);
- } catch (RemoteException re) {
- Log.e(TAG, "System unreachable to stop idle workload");
- }
- }
- }
- break;
- }
-
- case MSG_FINISH: {
- if (mCallbackBinder != null) {
- try {
- mCallbackBinder.idleFinished(mToken);
- } catch (RemoteException e) {
- Log.e(TAG, "System unreachable to finish idling");
- } finally {
- mCallbackBinder = null;
- }
- } else {
- Log.e(TAG, "finishIdle() called but the idle service is not started");
- }
- break;
- }
-
- default: {
- Slog.w(TAG, "Unknown message " + msg.what);
- }
- }
- }
- }
-
- /** @hide */
- @Override
- public final IBinder onBind(Intent intent) {
- return mBinder.asBinder();
- }
-
-}
diff --git a/core/java/android/app/task/ITaskCallback.aidl b/core/java/android/app/task/ITaskCallback.aidl
deleted file mode 100644
index d8a32fd..0000000
--- a/core/java/android/app/task/ITaskCallback.aidl
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Copyright 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.app.task;
-
-import android.app.task.ITaskService;
-import android.app.task.TaskParams;
-
-/**
- * The server side of the TaskManager IPC protocols. The app-side implementation
- * invokes on this interface to indicate completion of the (asynchronous) instructions
- * issued by the server.
- *
- * In all cases, the 'who' parameter is the caller's service binder, used to track
- * which Task Service instance is reporting.
- *
- * {@hide}
- */
-interface ITaskCallback {
- /**
- * Immediate callback to the system after sending a start signal, used to quickly detect ANR.
- *
- * @param taskId Unique integer used to identify this task.
- * @param ongoing True to indicate that the client is processing the task. False if the task is
- * complete
- */
- void acknowledgeStartMessage(int taskId, boolean ongoing);
- /**
- * Immediate callback to the system after sending a stop signal, used to quickly detect ANR.
- *
- * @param taskId Unique integer used to identify this task.
- * @param rescheulde Whether or not to reschedule this task.
- */
- void acknowledgeStopMessage(int taskId, boolean reschedule);
- /*
- * Tell the task manager that the client is done with its execution, so that it can go on to
- * the next one and stop attributing wakelock time to us etc.
- *
- * @param taskId Unique integer used to identify this task.
- * @param reschedule Whether or not to reschedule this task.
- */
- void taskFinished(int taskId, boolean reschedule);
-}
diff --git a/core/java/android/app/task/TaskManager.java b/core/java/android/app/task/TaskManager.java
deleted file mode 100644
index 00f57da..0000000
--- a/core/java/android/app/task/TaskManager.java
+++ /dev/null
@@ -1,72 +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.app.task;
-
-import java.util.List;
-
-import android.content.Context;
-
-/**
- * Class for scheduling various types of tasks with the scheduling framework on the device.
- *
- * <p>You do not
- * instantiate this class directly; instead, retrieve it through
- * {@link android.content.Context#getSystemService
- * Context.getSystemService(Context.TASK_SERVICE)}.
- */
-public abstract class TaskManager {
- /*
- * Returned from {@link #schedule(Task)} when an invalid parameter was supplied. This can occur
- * if the run-time for your task is too short, or perhaps the system can't resolve the
- * requisite {@link TaskService} in your package.
- */
- public static final int RESULT_FAILURE = 0;
- /**
- * Returned from {@link #schedule(Task)} if this application has made too many requests for
- * work over too short a time.
- */
- // TODO: Determine if this is necessary.
- public static final int RESULT_SUCCESS = 1;
-
- /**
- * @param task The task you wish scheduled. See
- * {@link android.app.task.Task.Builder Task.Builder} for more detail on the sorts of tasks
- * you can schedule.
- * @return If >0, this int returns the taskId of the successfully scheduled task.
- * Otherwise you have to compare the return value to the error codes defined in this class.
- */
- public abstract int schedule(Task task);
-
- /**
- * Cancel a task that is pending in the TaskManager.
- * @param taskId unique identifier for this task. Obtain this value from the tasks returned by
- * {@link #getAllPendingTasks()}.
- * @return
- */
- public abstract void cancel(int taskId);
-
- /**
- * Cancel all tasks that have been registered with the TaskManager by this package.
- */
- public abstract void cancelAll();
-
- /**
- * @return a list of all the tasks registered by this package that have not yet been executed.
- */
- public abstract List<Task> getAllPendingTasks();
-
-}
diff --git a/core/java/android/app/task/TaskParams.java b/core/java/android/app/task/TaskParams.java
deleted file mode 100644
index f4908c6..0000000
--- a/core/java/android/app/task/TaskParams.java
+++ /dev/null
@@ -1,91 +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.app.task;
-
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.PersistableBundle;
-
-/**
- * Contains the parameters used to configure/identify your task. You do not create this object
- * yourself, instead it is handed in to your application by the System.
- */
-public class TaskParams implements Parcelable {
-
- private final int taskId;
- private final PersistableBundle extras;
- private final IBinder callback;
-
- /** @hide */
- public TaskParams(int taskId, PersistableBundle extras, IBinder callback) {
- this.taskId = taskId;
- this.extras = extras;
- this.callback = callback;
- }
-
- /**
- * @return The unique id of this task, specified at creation time.
- */
- public int getTaskId() {
- return taskId;
- }
-
- /**
- * @return The extras you passed in when constructing this task with
- * {@link android.app.task.Task.Builder#setExtras(android.os.PersistableBundle)}. This will
- * never be null. If you did not set any extras this will be an empty bundle.
- */
- public PersistableBundle getExtras() {
- return extras;
- }
-
- /** @hide */
- public ITaskCallback getCallback() {
- return ITaskCallback.Stub.asInterface(callback);
- }
-
- private TaskParams(Parcel in) {
- taskId = in.readInt();
- extras = in.readPersistableBundle();
- callback = in.readStrongBinder();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(taskId);
- dest.writePersistableBundle(extras);
- dest.writeStrongBinder(callback);
- }
-
- public static final Creator<TaskParams> CREATOR = new Creator<TaskParams>() {
- @Override
- public TaskParams createFromParcel(Parcel in) {
- return new TaskParams(in);
- }
-
- @Override
- public TaskParams[] newArray(int size) {
- return new TaskParams[size];
- }
- };
-}
diff --git a/core/java/android/app/task/TaskService.java b/core/java/android/app/task/TaskService.java
deleted file mode 100644
index 8ce4484..0000000
--- a/core/java/android/app/task/TaskService.java
+++ /dev/null
@@ -1,257 +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.app.task;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-/**
- * <p>Entry point for the callback from the {@link android.app.task.TaskManager}.</p>
- * <p>This is the base class that handles asynchronous requests that were previously scheduled. You
- * are responsible for overriding {@link TaskService#onStartTask(TaskParams)}, which is where
- * you will implement your task logic.</p>
- * <p>This service executes each incoming task on a {@link android.os.Handler} running on your
- * application's main thread. This means that you <b>must</b> offload your execution logic to
- * another thread/handler/{@link android.os.AsyncTask} of your choosing. Not doing so will result
- * in blocking any future callbacks from the TaskManager - specifically
- * {@link #onStopTask(android.app.task.TaskParams)}, which is meant to inform you that the
- * scheduling requirements are no longer being met.</p>
- */
-public abstract class TaskService extends Service {
- private static final String TAG = "TaskService";
-
- /**
- * Task services must be protected with this permission:
- *
- * <pre class="prettyprint">
- * <service android:name="MyTaskService"
- * android:permission="android.permission.BIND_TASK_SERVICE" >
- * ...
- * </service>
- * </pre>
- *
- * <p>If a task service is declared in the manifest but not protected with this
- * permission, that service will be ignored by the OS.
- */
- public static final String PERMISSION_BIND =
- "android.permission.BIND_TASK_SERVICE";
-
- /**
- * Identifier for a message that will result in a call to
- * {@link #onStartTask(android.app.task.TaskParams)}.
- */
- private final int MSG_EXECUTE_TASK = 0;
- /**
- * Message that will result in a call to {@link #onStopTask(android.app.task.TaskParams)}.
- */
- private final int MSG_STOP_TASK = 1;
- /**
- * Message that the client has completed execution of this task.
- */
- private final int MSG_TASK_FINISHED = 2;
-
- /** Lock object for {@link #mHandler}. */
- private final Object mHandlerLock = new Object();
-
- /**
- * Handler we post tasks to. Responsible for calling into the client logic, and handling the
- * callback to the system.
- */
- @GuardedBy("mHandlerLock")
- TaskHandler mHandler;
-
- /** Binder for this service. */
- ITaskService mBinder = new ITaskService.Stub() {
- @Override
- public void startTask(TaskParams taskParams) {
- ensureHandler();
- Message m = Message.obtain(mHandler, MSG_EXECUTE_TASK, taskParams);
- m.sendToTarget();
- }
- @Override
- public void stopTask(TaskParams taskParams) {
- ensureHandler();
- Message m = Message.obtain(mHandler, MSG_STOP_TASK, taskParams);
- m.sendToTarget();
- }
- };
-
- /** @hide */
- void ensureHandler() {
- synchronized (mHandlerLock) {
- if (mHandler == null) {
- mHandler = new TaskHandler(getMainLooper());
- }
- }
- }
-
- /**
- * Runs on application's main thread - callbacks are meant to offboard work to some other
- * (app-specified) mechanism.
- * @hide
- */
- class TaskHandler extends Handler {
- TaskHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- final TaskParams params = (TaskParams) msg.obj;
- switch (msg.what) {
- case MSG_EXECUTE_TASK:
- try {
- boolean workOngoing = TaskService.this.onStartTask(params);
- ackStartMessage(params, workOngoing);
- } catch (Exception e) {
- Log.e(TAG, "Error while executing task: " + params.getTaskId());
- throw new RuntimeException(e);
- }
- break;
- case MSG_STOP_TASK:
- try {
- boolean ret = TaskService.this.onStopTask(params);
- ackStopMessage(params, ret);
- } catch (Exception e) {
- Log.e(TAG, "Application unable to handle onStopTask.", e);
- throw new RuntimeException(e);
- }
- break;
- case MSG_TASK_FINISHED:
- final boolean needsReschedule = (msg.arg2 == 1);
- ITaskCallback callback = params.getCallback();
- if (callback != null) {
- try {
- callback.taskFinished(params.getTaskId(), needsReschedule);
- } catch (RemoteException e) {
- Log.e(TAG, "Error reporting task finish to system: binder has gone" +
- "away.");
- }
- } else {
- Log.e(TAG, "finishTask() called for a nonexistent task id.");
- }
- break;
- default:
- Log.e(TAG, "Unrecognised message received.");
- break;
- }
- }
-
- private void ackStartMessage(TaskParams params, boolean workOngoing) {
- final ITaskCallback callback = params.getCallback();
- final int taskId = params.getTaskId();
- if (callback != null) {
- try {
- callback.acknowledgeStartMessage(taskId, workOngoing);
- } catch(RemoteException e) {
- Log.e(TAG, "System unreachable for starting task.");
- }
- } else {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Attempting to ack a task that has already been processed.");
- }
- }
- }
-
- private void ackStopMessage(TaskParams params, boolean reschedule) {
- final ITaskCallback callback = params.getCallback();
- final int taskId = params.getTaskId();
- if (callback != null) {
- try {
- callback.acknowledgeStopMessage(taskId, reschedule);
- } catch(RemoteException e) {
- Log.e(TAG, "System unreachable for stopping task.");
- }
- } else {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Attempting to ack a task that has already been processed.");
- }
- }
- }
- }
-
- /** @hide */
- public final IBinder onBind(Intent intent) {
- return mBinder.asBinder();
- }
-
- /**
- * Override this method with the callback logic for your task. Any such logic needs to be
- * performed on a separate thread, as this function is executed on your application's main
- * thread.
- *
- * @param params Parameters specifying info about this task, including the extras bundle you
- * optionally provided at task-creation time.
- * @return True if your service needs to process the work (on a separate thread). False if
- * there's no more work to be done for this task.
- */
- public abstract boolean onStartTask(TaskParams params);
-
- /**
- * This method is called if the system has determined that you must stop execution of your task
- * even before you've had a chance to call {@link #taskFinished(TaskParams, boolean)}.
- *
- * <p>This will happen if the requirements specified at schedule time are no longer met. For
- * example you may have requested WiFi with
- * {@link android.app.task.Task.Builder#setRequiredNetworkCapabilities(int)}, yet while your
- * task was executing the user toggled WiFi. Another example is if you had specified
- * {@link android.app.task.Task.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
- * idle maintenance window. You are solely responsible for the behaviour of your application
- * upon receipt of this message; your app will likely start to misbehave if you ignore it. One
- * immediate repercussion is that the system will cease holding a wakelock for you.</p>
- *
- * @param params Parameters specifying info about this task.
- * @return True to indicate to the TaskManager whether you'd like to reschedule this task based
- * on the retry criteria provided at task creation-time. False to drop the task. Regardless of
- * the value returned, your task must stop executing.
- */
- public abstract boolean onStopTask(TaskParams params);
-
- /**
- * Callback to inform the TaskManager you've finished executing. This can be called from any
- * thread, as it will ultimately be run on your application's main thread. When the system
- * receives this message it will release the wakelock being held.
- * <p>
- * You can specify post-execution behaviour to the scheduler here with
- * <code>needsReschedule </code>. This will apply a back-off timer to your task based on
- * the default, or what was set with
- * {@link android.app.task.Task.Builder#setBackoffCriteria(long, int)}. The original
- * requirements are always honoured even for a backed-off task. Note that a task running in
- * idle mode will not be backed-off. Instead what will happen is the task will be re-added
- * to the queue and re-executed within a future idle maintenance window.
- * </p>
- *
- * @param params Parameters specifying system-provided info about this task, this was given to
- * your application in {@link #onStartTask(TaskParams)}.
- * @param needsReschedule True if this task is complete, false if you want the TaskManager to
- * reschedule you.
- */
- public final void taskFinished(TaskParams params, boolean needsReschedule) {
- ensureHandler();
- Message m = Message.obtain(mHandler, MSG_TASK_FINISHED, params);
- m.arg2 = needsReschedule ? 1 : 0;
- m.sendToTarget();
- }
-}
\ No newline at end of file
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 7b709ac..5175490 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -90,6 +90,11 @@
public static final String ACTION_PLAYING_STATE_CHANGED =
"android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
+ /** @hide */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_AVRCP_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED";
+
/**
* A2DP sink device is streaming music. This state can be one of
* {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
new file mode 100644
index 0000000..2e27345
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -0,0 +1,432 @@
+/*
+ * 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.bluetooth;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides the public APIs to control the Bluetooth A2DP Sink
+ * profile.
+ *
+ *<p>BluetoothA2dpSink is a proxy object for controlling the Bluetooth A2DP Sink
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothA2dpSink proxy object.
+ *
+ * @hide
+ */
+public final class BluetoothA2dpSink implements BluetoothProfile {
+ private static final String TAG = "BluetoothA2dpSink";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ /**
+ * Intent used to broadcast the change in connection state of the A2DP Sink
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
+
+ /**
+ * Intent used to broadcast the change in the Playing state of the A2DP Sink
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ public static final String ACTION_PLAYING_STATE_CHANGED =
+ "android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED";
+
+ /**
+ * A2DP sink device is streaming music. This state can be one of
+ * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
+ * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
+ */
+ public static final int STATE_PLAYING = 10;
+
+ /**
+ * A2DP sink device is NOT streaming music. This state can be one of
+ * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
+ * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
+ */
+ public static final int STATE_NOT_PLAYING = 11;
+
+ /**
+ * Intent used to broadcast the change in the Playing state of the A2DP Sink
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_AUDIO_CONFIG} - The audio configuration for the remote device. </li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ public static final String ACTION_AUDIO_CONFIG_CHANGED =
+ "android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED";
+
+ /**
+ * Extra for the {@link #ACTION_AUDIO_CONFIG_CHANGED} intent.
+ *
+ * This extra represents the current audio configuration of the A2DP source device.
+ * {@see BluetoothAudioConfig}
+ */
+ public static final String EXTRA_AUDIO_CONFIG
+ = "android.bluetooth.a2dp-sink.profile.extra.AUDIO_CONFIG";
+
+ private Context mContext;
+ private ServiceListener mServiceListener;
+ private IBluetoothA2dpSink mService;
+ private BluetoothAdapter mAdapter;
+
+ final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (!up) {
+ if (VDBG) Log.d(TAG,"Unbinding service...");
+ synchronized (mConnection) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ } else {
+ synchronized (mConnection) {
+ try {
+ if (mService == null) {
+ if (VDBG) Log.d(TAG,"Binding service...");
+ doBind();
+ }
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+ };
+ /**
+ * Create a BluetoothA2dp proxy object for interacting with the local
+ * Bluetooth A2DP service.
+ *
+ */
+ /*package*/ BluetoothA2dpSink(Context context, ServiceListener l) {
+ mContext = context;
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ doBind();
+ }
+
+ boolean doBind() {
+ Intent intent = new Intent(IBluetoothA2dpSink.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);
+ return false;
+ }
+ return true;
+ }
+
+ /*package*/ void close() {
+ mServiceListener = null;
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (Exception e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ synchronized (mConnection) {
+ if (mService != null) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+
+ public void finalize() {
+ close();
+ }
+ /**
+ * Initiate connection to a profile of the remote bluetooth device.
+ *
+ * <p> Currently, the system supports only 1 connection to the
+ * A2DP profile. The API will automatically disconnect connected
+ * devices before connecting.
+ *
+ * <p> This API returns false in scenarios like the profile on the
+ * device is already connected or Bluetooth is not turned on.
+ * When this API returns true, it is guaranteed that
+ * connection state intent for the profile will be broadcasted with
+ * the state. Users can get the connection state of the profile
+ * from this intent.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error,
+ * true otherwise
+ * @hide
+ */
+ public boolean connect(BluetoothDevice device) {
+ if (DBG) log("connect(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.connect(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Initiate disconnection from a profile
+ *
+ * <p> This API will return false in scenarios like the profile on the
+ * Bluetooth device is not in connected state etc. When this API returns,
+ * true, it is guaranteed that the connection state change
+ * intent will be broadcasted with the state. Users can get the
+ * disconnection state of the profile from this intent.
+ *
+ * <p> If the disconnection is initiated by a remote device, the state
+ * will transition from {@link #STATE_CONNECTED} to
+ * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
+ * host (local) device the state will transition from
+ * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
+ * state {@link #STATE_DISCONNECTED}. The transition to
+ * {@link #STATE_DISCONNECTING} can be used to distinguish between the
+ * two scenarios.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error,
+ * true otherwise
+ * @hide
+ */
+ public boolean disconnect(BluetoothDevice device) {
+ if (DBG) log("disconnect(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.disconnect(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) log("getConnectedDevices()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (VDBG) log("getDevicesMatchingStates()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getConnectionState(BluetoothDevice device) {
+ if (VDBG) log("getState(" + device + ")");
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mService.getConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ /**
+ * Get the current audio configuration for the A2DP source device,
+ * or null if the device has no audio configuration
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param device Remote bluetooth device.
+ * @return audio configuration for the device, or null
+ *
+ * {@see BluetoothAudioConfig}
+ */
+ public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) {
+ if (VDBG) log("getAudioConfig(" + device + ")");
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mService.getAudioConfig(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return null;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return null;
+ }
+
+ /**
+ * Helper for converting a state to a string.
+ *
+ * For debug use only - strings are not internationalized.
+ * @hide
+ */
+ public static String stateToString(int state) {
+ switch (state) {
+ case STATE_DISCONNECTED:
+ return "disconnected";
+ case STATE_CONNECTING:
+ return "connecting";
+ case STATE_CONNECTED:
+ return "connected";
+ case STATE_DISCONNECTING:
+ return "disconnecting";
+ case STATE_PLAYING:
+ return "playing";
+ case STATE_NOT_PLAYING:
+ return "not playing";
+ default:
+ return "<unknown state " + state + ">";
+ }
+ }
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) Log.d(TAG, "Proxy object connected");
+ mService = IBluetoothA2dpSink.Stub.asInterface(service);
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.A2DP_SINK,
+ BluetoothA2dpSink.this);
+ }
+ }
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) Log.d(TAG, "Proxy object disconnected");
+ mService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP_SINK);
+ }
+ }
+ };
+
+ private boolean isEnabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 42c2aeb..ba42f51b 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-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.
@@ -1390,6 +1390,12 @@
} else if (profile == BluetoothProfile.A2DP) {
BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
return true;
+ } else if (profile == BluetoothProfile.A2DP_SINK) {
+ BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener);
+ return true;
+ } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
+ BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);
+ return true;
} else if (profile == BluetoothProfile.INPUT_DEVICE) {
BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
return true;
@@ -1402,6 +1408,9 @@
} else if (profile == BluetoothProfile.MAP) {
BluetoothMap map = new BluetoothMap(context, listener);
return true;
+ } else if (profile == BluetoothProfile.HEADSET_CLIENT) {
+ BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener);
+ return true;
} else {
return false;
}
@@ -1430,6 +1439,14 @@
BluetoothA2dp a2dp = (BluetoothA2dp)proxy;
a2dp.close();
break;
+ case BluetoothProfile.A2DP_SINK:
+ BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink)proxy;
+ a2dpSink.close();
+ break;
+ case BluetoothProfile.AVRCP_CONTROLLER:
+ BluetoothAvrcpController avrcp = (BluetoothAvrcpController)proxy;
+ avrcp.close();
+ break;
case BluetoothProfile.INPUT_DEVICE:
BluetoothInputDevice iDev = (BluetoothInputDevice)proxy;
iDev.close();
@@ -1454,6 +1471,10 @@
BluetoothMap map = (BluetoothMap)proxy;
map.close();
break;
+ case BluetoothProfile.HEADSET_CLIENT:
+ BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient)proxy;
+ headsetClient.close();
+ break;
}
}
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/bluetooth/BluetoothAudioConfig.aidl
similarity index 82%
copy from core/java/android/app/task/Task.aidl
copy to core/java/android/bluetooth/BluetoothAudioConfig.aidl
index 1f25439..63be5cf 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/core/java/android/bluetooth/BluetoothAudioConfig.aidl
@@ -1,5 +1,5 @@
-/**
- * Copyright (C) 2014 The Android Open Source Project
+/*
+ * Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-package android.app.task;
+package android.bluetooth;
-parcelable Task;
-
\ No newline at end of file
+parcelable BluetoothAudioConfig;
diff --git a/core/java/android/bluetooth/BluetoothAudioConfig.java b/core/java/android/bluetooth/BluetoothAudioConfig.java
new file mode 100644
index 0000000..03176b9
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAudioConfig.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents the audio configuration for a Bluetooth A2DP source device.
+ *
+ * {@see BluetoothA2dpSink}
+ *
+ * {@hide}
+ */
+public final class BluetoothAudioConfig implements Parcelable {
+
+ private final int mSampleRate;
+ private final int mChannelConfig;
+ private final int mAudioFormat;
+
+ public BluetoothAudioConfig(int sampleRate, int channelConfig, int audioFormat) {
+ mSampleRate = sampleRate;
+ mChannelConfig = channelConfig;
+ mAudioFormat = audioFormat;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothAudioConfig) {
+ BluetoothAudioConfig bac = (BluetoothAudioConfig)o;
+ return (bac.mSampleRate == mSampleRate &&
+ bac.mChannelConfig == mChannelConfig &&
+ bac.mAudioFormat == mAudioFormat);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return mSampleRate | (mChannelConfig << 24) | (mAudioFormat << 28);
+ }
+
+ @Override
+ public String toString() {
+ return "{mSampleRate:" + mSampleRate + ",mChannelConfig:" + mChannelConfig
+ + ",mAudioFormat:" + mAudioFormat + "}";
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<BluetoothAudioConfig> CREATOR =
+ new Parcelable.Creator<BluetoothAudioConfig>() {
+ public BluetoothAudioConfig createFromParcel(Parcel in) {
+ int sampleRate = in.readInt();
+ int channelConfig = in.readInt();
+ int audioFormat = in.readInt();
+ return new BluetoothAudioConfig(sampleRate, channelConfig, audioFormat);
+ }
+ public BluetoothAudioConfig[] newArray(int size) {
+ return new BluetoothAudioConfig[size];
+ }
+ };
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mSampleRate);
+ out.writeInt(mChannelConfig);
+ out.writeInt(mAudioFormat);
+ }
+
+ /**
+ * Returns the sample rate in samples per second
+ * @return sample rate
+ */
+ public int getSampleRate() {
+ return mSampleRate;
+ }
+
+ /**
+ * Returns the channel configuration (either {@link android.media.AudioFormat#CHANNEL_IN_MONO}
+ * or {@link android.media.AudioFormat#CHANNEL_IN_STEREO})
+ * @return channel configuration
+ */
+ public int getChannelConfig() {
+ return mChannelConfig;
+ }
+
+ /**
+ * Returns the channel audio format (either {@link android.media.AudioFormat#ENCODING_PCM_16BIT}
+ * or {@link android.media.AudioFormat#ENCODING_PCM_8BIT}
+ * @return audio format
+ */
+ public int getAudioFormat() {
+ return mAudioFormat;
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothAvrcp.java b/core/java/android/bluetooth/BluetoothAvrcp.java
new file mode 100644
index 0000000..44fe1b7
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAvrcp.java
@@ -0,0 +1,93 @@
+/*
+ * 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.bluetooth;
+
+/**
+ * This class contains constants for Bluetooth AVRCP profile.
+ *
+ * {@hide}
+ */
+public final class BluetoothAvrcp {
+
+ /*
+ * State flags for Passthrough commands
+ */
+ public static final int PASSTHROUGH_STATE_PRESS = 0;
+ public static final int PASSTHROUGH_STATE_RELEASE = 1;
+
+ /*
+ * Operation IDs for Passthrough commands
+ */
+ public static final int PASSTHROUGH_ID_SELECT = 0x00; /* select */
+ public static final int PASSTHROUGH_ID_UP = 0x01; /* up */
+ public static final int PASSTHROUGH_ID_DOWN = 0x02; /* down */
+ public static final int PASSTHROUGH_ID_LEFT = 0x03; /* left */
+ public static final int PASSTHROUGH_ID_RIGHT = 0x04; /* right */
+ public static final int PASSTHROUGH_ID_RIGHT_UP = 0x05; /* right-up */
+ public static final int PASSTHROUGH_ID_RIGHT_DOWN = 0x06; /* right-down */
+ public static final int PASSTHROUGH_ID_LEFT_UP = 0x07; /* left-up */
+ public static final int PASSTHROUGH_ID_LEFT_DOWN = 0x08; /* left-down */
+ public static final int PASSTHROUGH_ID_ROOT_MENU = 0x09; /* root menu */
+ public static final int PASSTHROUGH_ID_SETUP_MENU = 0x0A; /* setup menu */
+ public static final int PASSTHROUGH_ID_CONT_MENU = 0x0B; /* contents menu */
+ public static final int PASSTHROUGH_ID_FAV_MENU = 0x0C; /* favorite menu */
+ public static final int PASSTHROUGH_ID_EXIT = 0x0D; /* exit */
+ public static final int PASSTHROUGH_ID_0 = 0x20; /* 0 */
+ public static final int PASSTHROUGH_ID_1 = 0x21; /* 1 */
+ public static final int PASSTHROUGH_ID_2 = 0x22; /* 2 */
+ public static final int PASSTHROUGH_ID_3 = 0x23; /* 3 */
+ public static final int PASSTHROUGH_ID_4 = 0x24; /* 4 */
+ public static final int PASSTHROUGH_ID_5 = 0x25; /* 5 */
+ public static final int PASSTHROUGH_ID_6 = 0x26; /* 6 */
+ public static final int PASSTHROUGH_ID_7 = 0x27; /* 7 */
+ public static final int PASSTHROUGH_ID_8 = 0x28; /* 8 */
+ public static final int PASSTHROUGH_ID_9 = 0x29; /* 9 */
+ public static final int PASSTHROUGH_ID_DOT = 0x2A; /* dot */
+ public static final int PASSTHROUGH_ID_ENTER = 0x2B; /* enter */
+ public static final int PASSTHROUGH_ID_CLEAR = 0x2C; /* clear */
+ public static final int PASSTHROUGH_ID_CHAN_UP = 0x30; /* channel up */
+ public static final int PASSTHROUGH_ID_CHAN_DOWN = 0x31; /* channel down */
+ public static final int PASSTHROUGH_ID_PREV_CHAN = 0x32; /* previous channel */
+ public static final int PASSTHROUGH_ID_SOUND_SEL = 0x33; /* sound select */
+ public static final int PASSTHROUGH_ID_INPUT_SEL = 0x34; /* input select */
+ public static final int PASSTHROUGH_ID_DISP_INFO = 0x35; /* display information */
+ public static final int PASSTHROUGH_ID_HELP = 0x36; /* help */
+ public static final int PASSTHROUGH_ID_PAGE_UP = 0x37; /* page up */
+ public static final int PASSTHROUGH_ID_PAGE_DOWN = 0x38; /* page down */
+ public static final int PASSTHROUGH_ID_POWER = 0x40; /* power */
+ public static final int PASSTHROUGH_ID_VOL_UP = 0x41; /* volume up */
+ public static final int PASSTHROUGH_ID_VOL_DOWN = 0x42; /* volume down */
+ public static final int PASSTHROUGH_ID_MUTE = 0x43; /* mute */
+ public static final int PASSTHROUGH_ID_PLAY = 0x44; /* play */
+ public static final int PASSTHROUGH_ID_STOP = 0x45; /* stop */
+ public static final int PASSTHROUGH_ID_PAUSE = 0x46; /* pause */
+ public static final int PASSTHROUGH_ID_RECORD = 0x47; /* record */
+ public static final int PASSTHROUGH_ID_REWIND = 0x48; /* rewind */
+ public static final int PASSTHROUGH_ID_FAST_FOR = 0x49; /* fast forward */
+ public static final int PASSTHROUGH_ID_EJECT = 0x4A; /* eject */
+ public static final int PASSTHROUGH_ID_FORWARD = 0x4B; /* forward */
+ public static final int PASSTHROUGH_ID_BACKWARD = 0x4C; /* backward */
+ public static final int PASSTHROUGH_ID_ANGLE = 0x50; /* angle */
+ public static final int PASSTHROUGH_ID_SUBPICT = 0x51; /* subpicture */
+ public static final int PASSTHROUGH_ID_F1 = 0x71; /* F1 */
+ public static final int PASSTHROUGH_ID_F2 = 0x72; /* F2 */
+ public static final int PASSTHROUGH_ID_F3 = 0x73; /* F3 */
+ public static final int PASSTHROUGH_ID_F4 = 0x74; /* F4 */
+ public static final int PASSTHROUGH_ID_F5 = 0x75; /* F5 */
+ public static final int PASSTHROUGH_ID_VENDOR = 0x7E; /* vendor unique */
+ public static final int PASSTHROUGH_KEYPRESSED_RELEASE = 0x80;
+}
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
new file mode 100644
index 0000000..b53a8fc
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -0,0 +1,260 @@
+/*
+ * 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.bluetooth;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides the public APIs to control the Bluetooth AVRCP Controller
+ * profile.
+ *
+ *<p>BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothAvrcpController proxy object.
+ *
+ * {@hide}
+ */
+public final class BluetoothAvrcpController implements BluetoothProfile {
+ private static final String TAG = "BluetoothAvrcpController";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ /**
+ * Intent used to broadcast the change in connection state of the AVRCP Controller
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.acrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
+
+ private Context mContext;
+ private ServiceListener mServiceListener;
+ private IBluetoothAvrcpController mService;
+ private BluetoothAdapter mAdapter;
+
+ final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (!up) {
+ if (VDBG) Log.d(TAG,"Unbinding service...");
+ synchronized (mConnection) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ } else {
+ synchronized (mConnection) {
+ try {
+ if (mService == null) {
+ if (VDBG) Log.d(TAG,"Binding service...");
+ doBind();
+ }
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+ };
+
+ /**
+ * Create a BluetoothAvrcpController proxy object for interacting with the local
+ * Bluetooth AVRCP service.
+ *
+ */
+ /*package*/ BluetoothAvrcpController(Context context, ServiceListener l) {
+ mContext = context;
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ doBind();
+ }
+
+ boolean doBind() {
+ Intent intent = new Intent(IBluetoothAvrcpController.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth AVRCP Controller Service with " + intent);
+ return false;
+ }
+ return true;
+ }
+
+ /*package*/ void close() {
+ mServiceListener = null;
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (Exception e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ synchronized (mConnection) {
+ if (mService != null) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+
+ public void finalize() {
+ close();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) log("getConnectedDevices()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (VDBG) log("getDevicesMatchingStates()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getConnectionState(BluetoothDevice device) {
+ if (VDBG) log("getState(" + device + ")");
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mService.getConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
+ if (DBG) Log.d(TAG, "sendPassThroughCmd");
+ if (mService != null && isEnabled()) {
+ try {
+ mService.sendPassThroughCmd(device, keyCode, keyState);
+ return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in sendPassThroughCmd()", e);
+ return;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ }
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) Log.d(TAG, "Proxy object connected");
+ mService = IBluetoothAvrcpController.Stub.asInterface(service);
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.AVRCP_CONTROLLER,
+ BluetoothAvrcpController.this);
+ }
+ }
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) Log.d(TAG, "Proxy object disconnected");
+ mService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.AVRCP_CONTROLLER);
+ }
+ }
+ };
+
+ private boolean isEnabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 7f8d0ab..64d80a0 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -874,6 +874,26 @@
}
/**
+ * Returns whether there is an open connection to this device.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
+ *
+ * @return True if there is at least one open connection to this device.
+ * @hide
+ */
+ public boolean isConnected() {
+ if (sService == null) {
+ // BT is not enabled, we cannot be connected.
+ return false;
+ }
+ try {
+ return sService.isConnected(this);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ return false;
+ }
+ }
+
+ /**
* Get the Bluetooth class of the remote device.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
*
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
new file mode 100644
index 0000000..ff4ebee
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -0,0 +1,1167 @@
+/*
+ * 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.bluetooth;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Public API to control Hands Free Profile (HFP role only).
+ * <p>
+ * This class defines methods that shall be used by application to manage profile
+ * connection, calls states and calls actions.
+ * <p>
+ *
+ * @hide
+ * */
+public final class BluetoothHeadsetClient implements BluetoothProfile {
+ private static final String TAG = "BluetoothHeadsetClient";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ /**
+ * Intent sent whenever connection to remote changes.
+ *
+ * <p>It includes two extras:
+ * <code>BluetoothProfile.EXTRA_PREVIOUS_STATE</code>
+ * and <code>BluetoothProfile.EXTRA_STATE</code>, which
+ * are mandatory.
+ * <p>There are also non mandatory feature extras:
+ * {@link #EXTRA_AG_FEATURE_3WAY_CALLING},
+ * {@link #EXTRA_AG_FEATURE_VOICE_RECOGNITION},
+ * {@link #EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT},
+ * {@link #EXTRA_AG_FEATURE_REJECT_CALL},
+ * {@link #EXTRA_AG_FEATURE_ECC},
+ * {@link #EXTRA_AG_FEATURE_RESPONSE_AND_HOLD},
+ * {@link #EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL},
+ * {@link #EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL},
+ * {@link #EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT},
+ * {@link #EXTRA_AG_FEATURE_MERGE},
+ * {@link #EXTRA_AG_FEATURE_MERGE_AND_DETACH},
+ * sent as boolean values only when <code>EXTRA_STATE</code>
+ * is set to <code>STATE_CONNECTED</code>.</p>
+ *
+ * <p>Note that features supported by AG are being sent as
+ * booleans with value <code>true</code>,
+ * and not supported ones are <strong>not</strong> being sent at all.</p>
+ */
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED";
+
+ /**
+ * Intent sent whenever audio state changes.
+ *
+ * <p>It includes two mandatory extras:
+ * {@link BluetoothProfile.EXTRA_STATE},
+ * {@link BluetoothProfile.EXTRA_PREVIOUS_STATE},
+ * with possible values:
+ * {@link #STATE_AUDIO_CONNECTING},
+ * {@link #STATE_AUDIO_CONNECTED},
+ * {@link #STATE_AUDIO_DISCONNECTED}</p>
+ * <p>When <code>EXTRA_STATE</code> is set
+ * to </code>STATE_AUDIO_CONNECTED</code>,
+ * it also includes {@link #EXTRA_AUDIO_WBS}
+ * indicating wide band speech support.</p>
+ */
+ public static final String ACTION_AUDIO_STATE_CHANGED =
+ "android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED";
+
+ /**
+ * Intent sending updates of the Audio Gateway state.
+ * Each extra is being sent only when value it
+ * represents has been changed recently on AG.
+ * <p>It can contain one or more of the following extras:
+ * {@link #EXTRA_NETWORK_STATUS},
+ * {@link #EXTRA_NETWORK_SIGNAL_STRENGTH},
+ * {@link #EXTRA_NETWORK_ROAMING},
+ * {@link #EXTRA_BATTERY_LEVEL},
+ * {@link #EXTRA_OPERATOR_NAME},
+ * {@link #EXTRA_VOICE_RECOGNITION},
+ * {@link #EXTRA_IN_BAND_RING}</p>
+ */
+ public static final String ACTION_AG_EVENT =
+ "android.bluetooth.headsetclient.profile.action.AG_EVENT";
+
+ /**
+ * Intent sent whenever state of a call changes.
+ *
+ * <p>It includes:
+ * {@link #EXTRA_CALL},
+ * with value of {@link BluetoothHeadsetClientCall} instance,
+ * representing actual call state.</p>
+ */
+ public static final String ACTION_CALL_CHANGED =
+ "android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED";
+
+ /**
+ * Intent that notifies about the result of the last issued action.
+ * Please note that not every action results in explicit action result code being sent.
+ * Instead other notifications about new Audio Gateway state might be sent,
+ * like <code>ACTION_AG_EVENT</code> with <code>EXTRA_VOICE_RECOGNITION</code> value
+ * when for example user started voice recognition from HF unit.
+ */
+ public static final String ACTION_RESULT =
+ "android.bluetooth.headsetclient.profile.action.RESULT";
+
+ /**
+ * Intent that notifies about the number attached to the last voice tag
+ * recorded on AG.
+ *
+ * <p>It contains:
+ * {@link #EXTRA_NUMBER},
+ * with a <code>String</code> value representing phone number.</p>
+ */
+ public static final String ACTION_LAST_VTAG =
+ "android.bluetooth.headsetclient.profile.action.LAST_VTAG";
+
+ public static final int STATE_AUDIO_DISCONNECTED = 0;
+ public static final int STATE_AUDIO_CONNECTING = 1;
+ public static final int STATE_AUDIO_CONNECTED = 2;
+
+ /**
+ * Extra with information if connected audio is WBS.
+ * <p>Possible values: <code>true</code>,
+ * <code>false</code>.</p>
+ */
+ public static final String EXTRA_AUDIO_WBS =
+ "android.bluetooth.headsetclient.extra.AUDIO_WBS";
+
+ /**
+ * Extra for AG_EVENT indicates network status.
+ * <p>Value: 0 - network unavailable,
+ * 1 - network available </p>
+ */
+ public static final String EXTRA_NETWORK_STATUS =
+ "android.bluetooth.headsetclient.extra.NETWORK_STATUS";
+ /**
+ * Extra for AG_EVENT intent indicates network signal strength.
+ * <p>Value: <code>Integer</code> representing signal strength.</p>
+ */
+ public static final String EXTRA_NETWORK_SIGNAL_STRENGTH =
+ "android.bluetooth.headsetclient.extra.NETWORK_SIGNAL_STRENGTH";
+ /**
+ * Extra for AG_EVENT intent indicates roaming state.
+ * <p>Value: 0 - no roaming
+ * 1 - active roaming</p>
+ */
+ public static final String EXTRA_NETWORK_ROAMING =
+ "android.bluetooth.headsetclient.extra.NETWORK_ROAMING";
+ /**
+ * Extra for AG_EVENT intent indicates the battery level.
+ * <p>Value: <code>Integer</code> representing signal strength.</p>
+ */
+ public static final String EXTRA_BATTERY_LEVEL =
+ "android.bluetooth.headsetclient.extra.BATTERY_LEVEL";
+ /**
+ * Extra for AG_EVENT intent indicates operator name.
+ * <p>Value: <code>String</code> representing operator name.</p>
+ */
+ public static final String EXTRA_OPERATOR_NAME =
+ "android.bluetooth.headsetclient.extra.OPERATOR_NAME";
+ /**
+ * Extra for AG_EVENT intent indicates voice recognition state.
+ * <p>Value:
+ * 0 - voice recognition stopped,
+ * 1 - voice recognition started.</p>
+ */
+ public static final String EXTRA_VOICE_RECOGNITION =
+ "android.bluetooth.headsetclient.extra.VOICE_RECOGNITION";
+ /**
+ * Extra for AG_EVENT intent indicates in band ring state.
+ * <p>Value:
+ * 0 - in band ring tone not supported, or
+ * 1 - in band ring tone supported.</p>
+ */
+ public static final String EXTRA_IN_BAND_RING =
+ "android.bluetooth.headsetclient.extra.IN_BAND_RING";
+
+ /**
+ * Extra for AG_EVENT intent indicates subscriber info.
+ * <p>Value: <code>String</code> containing subscriber information.</p>
+ */
+ public static final String EXTRA_SUBSCRIBER_INFO =
+ "android.bluetooth.headsetclient.extra.SUBSCRIBER_INFO";
+
+ /**
+ * Extra for AG_CALL_CHANGED intent indicates the
+ * {@link BluetoothHeadsetClientCall} object that has changed.
+ */
+ public static final String EXTRA_CALL =
+ "android.bluetooth.headsetclient.extra.CALL";
+
+ /**
+ * Extra for ACTION_LAST_VTAG intent.
+ * <p>Value: <code>String</code> representing phone number
+ * corresponding to last voice tag recorded on AG</p>
+ */
+ public static final String EXTRA_NUMBER =
+ "android.bluetooth.headsetclient.extra.NUMBER";
+
+ /**
+ * Extra for ACTION_RESULT intent that shows the result code of
+ * last issued action.
+ * <p>Possible results:
+ * {@link #ACTION_RESULT_OK},
+ * {@link #ACTION_RESULT_ERROR},
+ * {@link #ACTION_RESULT_ERROR_NO_CARRIER},
+ * {@link #ACTION_RESULT_ERROR_BUSY},
+ * {@link #ACTION_RESULT_ERROR_NO_ANSWER},
+ * {@link #ACTION_RESULT_ERROR_DELAYED},
+ * {@link #ACTION_RESULT_ERROR_BLACKLISTED},
+ * {@link #ACTION_RESULT_ERROR_CME}</p>
+ */
+ public static final String EXTRA_RESULT_CODE =
+ "android.bluetooth.headsetclient.extra.RESULT_CODE";
+
+ /**
+ * Extra for ACTION_RESULT intent that shows the extended result code of
+ * last issued action.
+ * <p>Value: <code>Integer</code> - error code.</p>
+ */
+ public static final String EXTRA_CME_CODE =
+ "android.bluetooth.headsetclient.extra.CME_CODE";
+
+ /* Extras for AG_FEATURES, extras type is boolean */
+ // TODO verify if all of those are actually useful
+ /**
+ * AG feature: three way calling.
+ */
+ public final static String EXTRA_AG_FEATURE_3WAY_CALLING =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_3WAY_CALLING";
+ /**
+ * AG feature: voice recognition.
+ */
+ public final static String EXTRA_AG_FEATURE_VOICE_RECOGNITION =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_VOICE_RECOGNITION";
+ /**
+ * AG feature: fetching phone number for voice tagging procedure.
+ */
+ public final static String EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT";
+ /**
+ * AG feature: ability to reject incoming call.
+ */
+ public final static String EXTRA_AG_FEATURE_REJECT_CALL =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_REJECT_CALL";
+ /**
+ * AG feature: enhanced call handling (terminate specific call, private consultation).
+ */
+ public final static String EXTRA_AG_FEATURE_ECC =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ECC";
+ /**
+ * AG feature: response and hold.
+ */
+ public final static String EXTRA_AG_FEATURE_RESPONSE_AND_HOLD =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RESPONSE_AND_HOLD";
+ /**
+ * AG call handling feature: accept held or waiting call in three way calling scenarios.
+ */
+ public final static String EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL";
+ /**
+ * AG call handling feature: release held or waiting call in three way calling scenarios.
+ */
+ public final static String EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL";
+ /**
+ * AG call handling feature: release active call and accept held or waiting call in three way
+ * calling scenarios.
+ */
+ public final static String EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT";
+ /**
+ * AG call handling feature: merge two calls, held and active - multi party conference mode.
+ */
+ public final static String EXTRA_AG_FEATURE_MERGE =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_MERGE";
+ /**
+ * AG call handling feature: merge calls and disconnect from multi party
+ * conversation leaving peers connected to each other.
+ * Note that this feature needs to be supported by mobile network operator
+ * as it requires connection and billing transfer.
+ */
+ public final static String EXTRA_AG_FEATURE_MERGE_AND_DETACH =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_MERGE_AND_DETACH";
+
+ /* Action result codes */
+ public final static int ACTION_RESULT_OK = 0;
+ public final static int ACTION_RESULT_ERROR = 1;
+ public final static int ACTION_RESULT_ERROR_NO_CARRIER = 2;
+ public final static int ACTION_RESULT_ERROR_BUSY = 3;
+ public final static int ACTION_RESULT_ERROR_NO_ANSWER = 4;
+ public final static int ACTION_RESULT_ERROR_DELAYED = 5;
+ public final static int ACTION_RESULT_ERROR_BLACKLISTED = 6;
+ public final static int ACTION_RESULT_ERROR_CME = 7;
+
+ /* Detailed CME error codes */
+ public final static int CME_PHONE_FAILURE = 0;
+ public final static int CME_NO_CONNECTION_TO_PHONE = 1;
+ public final static int CME_OPERATION_NOT_ALLOWED = 3;
+ public final static int CME_OPERATION_NOT_SUPPORTED = 4;
+ public final static int CME_PHSIM_PIN_REQUIRED = 5;
+ public final static int CME_PHFSIM_PIN_REQUIRED = 6;
+ public final static int CME_PHFSIM_PUK_REQUIRED = 7;
+ public final static int CME_SIM_NOT_INSERTED = 10;
+ public final static int CME_SIM_PIN_REQUIRED = 11;
+ public final static int CME_SIM_PUK_REQUIRED = 12;
+ public final static int CME_SIM_FAILURE = 13;
+ public final static int CME_SIM_BUSY = 14;
+ public final static int CME_SIM_WRONG = 15;
+ public final static int CME_INCORRECT_PASSWORD = 16;
+ public final static int CME_SIM_PIN2_REQUIRED = 17;
+ public final static int CME_SIM_PUK2_REQUIRED = 18;
+ public final static int CME_MEMORY_FULL = 20;
+ public final static int CME_INVALID_INDEX = 21;
+ public final static int CME_NOT_FOUND = 22;
+ public final static int CME_MEMORY_FAILURE = 23;
+ public final static int CME_TEXT_STRING_TOO_LONG = 24;
+ public final static int CME_INVALID_CHARACTER_IN_TEXT_STRING = 25;
+ public final static int CME_DIAL_STRING_TOO_LONG = 26;
+ public final static int CME_INVALID_CHARACTER_IN_DIAL_STRING = 27;
+ public final static int CME_NO_NETWORK_SERVICE = 30;
+ public final static int CME_NETWORK_TIMEOUT = 31;
+ public final static int CME_EMERGENCY_SERVICE_ONLY = 32;
+ public final static int CME_NO_SIMULTANOUS_VOIP_CS_CALLS = 33;
+ public final static int CME_NOT_SUPPORTED_FOR_VOIP = 34;
+ public final static int CME_SIP_RESPONSE_CODE = 35;
+ public final static int CME_NETWORK_PERSONALIZATION_PIN_REQUIRED = 40;
+ public final static int CME_NETWORK_PERSONALIZATION_PUK_REQUIRED = 41;
+ public final static int CME_NETWORK_SUBSET_PERSONALIZATION_PIN_REQUIRED = 42;
+ public final static int CME_NETWORK_SUBSET_PERSONALIZATION_PUK_REQUIRED = 43;
+ public final static int CME_SERVICE_PROVIDER_PERSONALIZATION_PIN_REQUIRED = 44;
+ public final static int CME_SERVICE_PROVIDER_PERSONALIZATION_PUK_REQUIRED = 45;
+ public final static int CME_CORPORATE_PERSONALIZATION_PIN_REQUIRED = 46;
+ public final static int CME_CORPORATE_PERSONALIZATION_PUK_REQUIRED = 47;
+ public final static int CME_HIDDEN_KEY_REQUIRED = 48;
+ public final static int CME_EAP_NOT_SUPPORTED = 49;
+ public final static int CME_INCORRECT_PARAMETERS = 50;
+
+ /* Action policy for other calls when accepting call */
+ public static final int CALL_ACCEPT_NONE = 0;
+ public static final int CALL_ACCEPT_HOLD = 1;
+ public static final int CALL_ACCEPT_TERMINATE = 2;
+
+ private Context mContext;
+ private ServiceListener mServiceListener;
+ private IBluetoothHeadsetClient mService;
+ private BluetoothAdapter mAdapter;
+
+ final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ @Override
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (!up) {
+ if (VDBG) Log.d(TAG,"Unbinding service...");
+ synchronized (mConnection) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ } else {
+ synchronized (mConnection) {
+ try {
+ if (mService == null) {
+ if (VDBG) Log.d(TAG,"Binding service...");
+ Intent intent = new Intent(IBluetoothHeadsetClient.class.getName());
+ doBind();
+ }
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+ };
+
+ /**
+ * Create a BluetoothHeadsetClient proxy object.
+ */
+ /*package*/ BluetoothHeadsetClient(Context context, ServiceListener l) {
+ mContext = context;
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ doBind();
+ }
+
+ boolean doBind() {
+ Intent intent = new Intent(IBluetoothHeadsetClient.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth Headset Client Service with " + intent);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Close the connection to the backing service.
+ * Other public functions of BluetoothHeadsetClient will return default error
+ * results once close() has been called. Multiple invocations of close()
+ * are ok.
+ */
+ /*package*/ void close() {
+ if (VDBG) log("close()");
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (Exception e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ synchronized (mConnection) {
+ if (mService != null) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ mServiceListener = null;
+ }
+
+ /**
+ * Connects to remote device.
+ *
+ * Currently, the system supports only 1 connection. So, in case of the
+ * second connection, this implementation will disconnect already connected
+ * device automatically and will process the new one.
+ *
+ * @param device a remote device we want connect to
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CONNECTION_STATE_CHANGED}
+ * intent.
+ */
+ public boolean connect(BluetoothDevice device) {
+ if (DBG) log("connect(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.connect(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Disconnects remote device
+ *
+ * @param device a remote device we want disconnect
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CONNECTION_STATE_CHANGED}
+ * intent.
+ */
+ public boolean disconnect(BluetoothDevice device) {
+ if (DBG) log("disconnect(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.disconnect(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Return the list of connected remote devices
+ *
+ * @return list of connected devices; empty list if nothing is connected.
+ */
+ @Override
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) log("getConnectedDevices()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * Returns list of remote devices in a particular state
+ *
+ * @param states collection of states
+ * @return list of devices that state matches the states listed in
+ * <code>states</code>; empty list if nothing matches the
+ * <code>states</code>
+ */
+ @Override
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (VDBG) log("getDevicesMatchingStates()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * Returns state of the <code>device</code>
+ *
+ * @param device a remote device
+ * @return the state of connection of the device
+ */
+ @Override
+ public int getConnectionState(BluetoothDevice device) {
+ if (VDBG) log("getConnectionState(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.getConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ /**
+ * Set priority of the profile
+ *
+ * The device should already be paired.
+ */
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setPriority(" + device + ", " + priority + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ if (priority != BluetoothProfile.PRIORITY_OFF &&
+ priority != BluetoothProfile.PRIORITY_ON) {
+ return false;
+ }
+ try {
+ return mService.setPriority(device, priority);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Get the priority of the profile.
+ */
+ public int getPriority(BluetoothDevice device) {
+ if (VDBG) log("getPriority(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.getPriority(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return PRIORITY_OFF;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return PRIORITY_OFF;
+ }
+
+ /**
+ * Starts voice recognition.
+ *
+ * @param device remote device
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_AG_EVENT}
+ * intent.
+ *
+ * <p>Feature required for successful execution is being reported by:
+ * {@link #EXTRA_AG_FEATURE_VOICE_RECOGNITION}.
+ * This method invocation will fail silently when feature is not supported.</p>
+ */
+ public boolean startVoiceRecognition(BluetoothDevice device) {
+ if (DBG) log("startVoiceRecognition()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.startVoiceRecognition(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Stops voice recognition.
+ *
+ * @param device remote device
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_AG_EVENT}
+ * intent.
+ *
+ * <p>Feature required for successful execution is being reported by:
+ * {@link #EXTRA_AG_FEATURE_VOICE_RECOGNITION}.
+ * This method invocation will fail silently when feature is not supported.</p>
+ */
+ public boolean stopVoiceRecognition(BluetoothDevice device) {
+ if (DBG) log("stopVoiceRecognition()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.stopVoiceRecognition(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Returns list of all calls in any state.
+ *
+ * @param device remote device
+ * @return list of calls; empty list if none call exists
+ */
+ public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) {
+ if (DBG) log("getCurrentCalls()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.getCurrentCalls(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return null;
+ }
+
+ /**
+ * Returns list of current values of AG indicators.
+ *
+ * @param device remote device
+ * @return bundle of AG indicators; null if device is not in
+ * CONNECTED state
+ */
+ public Bundle getCurrentAgEvents(BluetoothDevice device) {
+ if (DBG) log("getCurrentCalls()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.getCurrentAgEvents(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return null;
+ }
+
+ /**
+ * Accepts a call
+ *
+ * @param device remote device
+ * @param flag action policy while accepting a call. Possible values
+ * {@link #CALL_ACCEPT_NONE}, {@link #CALL_ACCEPT_HOLD},
+ * {@link #CALL_ACCEPT_TERMINATE}
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent.
+ */
+ public boolean acceptCall(BluetoothDevice device, int flag) {
+ if (DBG) log("acceptCall()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.acceptCall(device, flag);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Holds a call.
+ *
+ * @param device remote device
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent.
+ */
+ public boolean holdCall(BluetoothDevice device) {
+ if (DBG) log("holdCall()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.holdCall(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Rejects a call.
+ *
+ * @param device remote device
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent.
+ *
+ * <p>Feature required for successful execution is being reported by:
+ * {@link #EXTRA_AG_FEATURE_REJECT_CALL}.
+ * This method invocation will fail silently when feature is not supported.</p>
+ */
+ public boolean rejectCall(BluetoothDevice device) {
+ if (DBG) log("rejectCall()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.rejectCall(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Terminates a specified call.
+ *
+ * Works only when Extended Call Control is supported by Audio Gateway.
+ *
+ * @param device remote device
+ * @param index index of the call to be terminated
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent.
+ *
+ * <p>Feature required for successful execution is being reported by:
+ * {@link #EXTRA_AG_FEATURE_ECC}.
+ * This method invocation will fail silently when feature is not supported.</p>
+ */
+ public boolean terminateCall(BluetoothDevice device, int index) {
+ if (DBG) log("terminateCall()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.terminateCall(device, index);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Enters private mode with a specified call.
+ *
+ * Works only when Extended Call Control is supported by Audio Gateway.
+ *
+ * @param device remote device
+ * @param index index of the call to connect in private mode
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent.
+ *
+ * <p>Feature required for successful execution is being reported by:
+ * {@link #EXTRA_AG_FEATURE_ECC}.
+ * This method invocation will fail silently when feature is not supported.</p>
+ */
+ public boolean enterPrivateMode(BluetoothDevice device, int index) {
+ if (DBG) log("enterPrivateMode()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.enterPrivateMode(device, index);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Performs explicit call transfer.
+ *
+ * That means connect other calls and disconnect.
+ *
+ * @param device remote device
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent.
+ *
+ * <p>Feature required for successful execution is being reported by:
+ * {@link #EXTRA_AG_FEATURE_MERGE_AND_DETACH}.
+ * This method invocation will fail silently when feature is not supported.</p>
+ */
+ public boolean explicitCallTransfer(BluetoothDevice device) {
+ if (DBG) log("explicitCallTransfer()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.explicitCallTransfer(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Redials last number from Audio Gateway.
+ *
+ * @param device remote device
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent in case of success; {@link #ACTION_RESULT} is sent
+ * otherwise;
+ */
+ public boolean redial(BluetoothDevice device) {
+ if (DBG) log("redial()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.redial(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Places a call with specified number.
+ *
+ * @param device remote device
+ * @param number valid phone number
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent in case of success; {@link #ACTION_RESULT} is sent
+ * otherwise;
+ */
+ public boolean dial(BluetoothDevice device, String number) {
+ if (DBG) log("dial()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.dial(device, number);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Places a call to the number under specified memory location.
+ *
+ * @param device remote device
+ * @param location valid memory location
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent in case of success; {@link #ACTION_RESULT} is sent
+ * otherwise;
+ */
+ public boolean dialMemory(BluetoothDevice device, int location) {
+ if (DBG) log("dialMemory()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.dialMemory(device, location);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Sends DTMF code.
+ *
+ * Possible code values : 0,1,2,3,4,5,6,7,8,9,A,B,C,D,*,#
+ *
+ * @param device remote device
+ * @param code ASCII code
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_RESULT} intent;
+ */
+ public boolean sendDTMF(BluetoothDevice device, byte code) {
+ if (DBG) log("sendDTMF()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.sendDTMF(device, code);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Get a number corresponding to last voice tag recorded on AG.
+ *
+ * @param device remote device
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_LAST_VTAG}
+ * or {@link #ACTION_RESULT} intent;
+ *
+ * <p>Feature required for successful execution is being reported by:
+ * {@link #EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT}.
+ * This method invocation will fail silently when feature is not supported.</p>
+ */
+ public boolean getLastVoiceTagNumber(BluetoothDevice device) {
+ if (DBG) log("getLastVoiceTagNumber()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.getLastVoiceTagNumber(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Accept the incoming connection.
+ */
+ public boolean acceptIncomingConnect(BluetoothDevice device) {
+ if (DBG) log("acceptIncomingConnect");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.acceptIncomingConnect(device);
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * Reject the incoming connection.
+ */
+ public boolean rejectIncomingConnect(BluetoothDevice device) {
+ if (DBG) log("rejectIncomingConnect");
+ if (mService != null) {
+ try {
+ return mService.rejectIncomingConnect(device);
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * Returns current audio state of Audio Gateway.
+ *
+ * Note: This is an internal function and shouldn't be exposed
+ */
+ public int getAudioState(BluetoothDevice device) {
+ if (VDBG) log("getAudioState");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getAudioState(device);
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED;
+ }
+
+ /**
+ * Initiates a connection of audio channel.
+ *
+ * It setup SCO channel with remote connected Handsfree AG device.
+ *
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED}
+ * intent;
+ */
+ public boolean connectAudio() {
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.connectAudio();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * Disconnects audio channel.
+ *
+ * It tears down the SCO channel from remote AG device.
+ *
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED}
+ * intent;
+ */
+ public boolean disconnectAudio() {
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.disconnectAudio();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * Get Audio Gateway features
+ *
+ * @param device remote device
+ * @return bundle of AG features; null if no service or
+ * AG not connected
+ */
+ public Bundle getCurrentAgFeatures(BluetoothDevice device) {
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getCurrentAgFeatures(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return null;
+ }
+
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) Log.d(TAG, "Proxy object connected");
+ mService = IBluetoothHeadsetClient.Stub.asInterface(service);
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.HEADSET_CLIENT,
+ BluetoothHeadsetClient.this);
+ }
+ }
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) Log.d(TAG, "Proxy object disconnected");
+ mService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET_CLIENT);
+ }
+ }
+ };
+
+ private boolean isEnabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/bluetooth/BluetoothHeadsetClientCall.aidl
similarity index 89%
copy from core/java/android/app/task/Task.aidl
copy to core/java/android/bluetooth/BluetoothHeadsetClientCall.aidl
index 1f25439..35f7923 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.aidl
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,8 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.bluetooth;
-package android.app.task;
-
-parcelable Task;
-
\ No newline at end of file
+parcelable BluetoothHeadsetClientCall;
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
new file mode 100644
index 0000000..a15bd97
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
@@ -0,0 +1,218 @@
+/*
+ * 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.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class represents a single call, its state and properties.
+ * It implements {@link Parcelable} for inter-process message passing.
+ * @hide
+ */
+public final class BluetoothHeadsetClientCall implements Parcelable {
+
+ /* Call state */
+ /**
+ * Call is active.
+ */
+ public static final int CALL_STATE_ACTIVE = 0;
+ /**
+ * Call is in held state.
+ */
+ public static final int CALL_STATE_HELD = 1;
+ /**
+ * Outgoing call that is being dialed right now.
+ */
+ public static final int CALL_STATE_DIALING = 2;
+ /**
+ * Outgoing call that remote party has already been alerted about.
+ */
+ public static final int CALL_STATE_ALERTING = 3;
+ /**
+ * Incoming call that can be accepted or rejected.
+ */
+ public static final int CALL_STATE_INCOMING = 4;
+ /**
+ * Waiting call state when there is already an active call.
+ */
+ public static final int CALL_STATE_WAITING = 5;
+ /**
+ * Call that has been held by response and hold
+ * (see Bluetooth specification for further references).
+ */
+ public static final int CALL_STATE_HELD_BY_RESPONSE_AND_HOLD = 6;
+ /**
+ * Call that has been already terminated and should not be referenced as a valid call.
+ */
+ public static final int CALL_STATE_TERMINATED = 7;
+
+ private final int mId;
+ private int mState;
+ private String mNumber;
+ private boolean mMultiParty;
+ private final boolean mOutgoing;
+
+ /**
+ * Creates BluetoothHeadsetClientCall instance.
+ */
+ public BluetoothHeadsetClientCall(int id, int state, String number, boolean multiParty,
+ boolean outgoing) {
+ mId = id;
+ mState = state;
+ mNumber = number != null ? number : "";
+ mMultiParty = multiParty;
+ mOutgoing = outgoing;
+ }
+
+ /**
+ * Sets call's state.
+ *
+ * <p>Note: This is an internal function and shouldn't be exposed</p>
+ *
+ * @param state new call state.
+ */
+ public void setState(int state) {
+ mState = state;
+ }
+
+ /**
+ * Sets call's number.
+ *
+ * <p>Note: This is an internal function and shouldn't be exposed</p>
+ *
+ * @param number String representing phone number.
+ */
+ public void setNumber(String number) {
+ mNumber = number;
+ }
+
+ /**
+ * Sets this call as multi party call.
+ *
+ * <p>Note: This is an internal function and shouldn't be exposed</p>
+ *
+ * @param multiParty if <code>true</code> sets this call as a part
+ * of multi party conference.
+ */
+ public void setMultiParty(boolean multiParty) {
+ mMultiParty = multiParty;
+ }
+
+ /**
+ * Gets call's Id.
+ *
+ * @return call id.
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Gets call's current state.
+ *
+ * @return state of this particular phone call.
+ */
+ public int getState() {
+ return mState;
+ }
+
+ /**
+ * Gets call's number.
+ *
+ * @return string representing phone number.
+ */
+ public String getNumber() {
+ return mNumber;
+ }
+
+ /**
+ * Checks if call is an active call in a conference mode (aka multi party).
+ *
+ * @return <code>true</code> if call is a multi party call,
+ * <code>false</code> otherwise.
+ */
+ public boolean isMultiParty() {
+ return mMultiParty;
+ }
+
+ /**
+ * Checks if this call is an outgoing call.
+ *
+ * @return <code>true</code> if its outgoing call,
+ * <code>false</code> otherwise.
+ */
+ public boolean isOutgoing() {
+ return mOutgoing;
+ }
+
+ public String toString() {
+ StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mId: ");
+ builder.append(mId);
+ builder.append(", mState: ");
+ switch (mState) {
+ case CALL_STATE_ACTIVE: builder.append("ACTIVE"); break;
+ case CALL_STATE_HELD: builder.append("HELD"); break;
+ case CALL_STATE_DIALING: builder.append("DIALING"); break;
+ case CALL_STATE_ALERTING: builder.append("ALERTING"); break;
+ case CALL_STATE_INCOMING: builder.append("INCOMING"); break;
+ case CALL_STATE_WAITING: builder.append("WAITING"); break;
+ case CALL_STATE_HELD_BY_RESPONSE_AND_HOLD: builder.append("HELD_BY_RESPONSE_AND_HOLD"); break;
+ case CALL_STATE_TERMINATED: builder.append("TERMINATED"); break;
+ default: builder.append(mState); break;
+ }
+ builder.append(", mNumber: ");
+ builder.append(mNumber);
+ builder.append(", mMultiParty: ");
+ builder.append(mMultiParty);
+ builder.append(", mOutgoing: ");
+ builder.append(mOutgoing);
+ builder.append("}");
+ return builder.toString();
+ }
+
+ /**
+ * {@link Parcelable.Creator} interface implementation.
+ */
+ public static final Parcelable.Creator<BluetoothHeadsetClientCall> CREATOR =
+ new Parcelable.Creator<BluetoothHeadsetClientCall>() {
+ @Override
+ public BluetoothHeadsetClientCall createFromParcel(Parcel in) {
+ return new BluetoothHeadsetClientCall(in.readInt(), in.readInt(),
+ in.readString(), in.readInt() == 1, in.readInt() == 1);
+ }
+
+ @Override
+ public BluetoothHeadsetClientCall[] newArray(int size) {
+ return new BluetoothHeadsetClientCall[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mId);
+ out.writeInt(mState);
+ out.writeString(mNumber);
+ out.writeInt(mMultiParty ? 1 : 0);
+ out.writeInt(mOutgoing ? 1 : 0);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index d898060..1367405 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2010-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.
@@ -110,6 +110,18 @@
public static final int A2DP_SINK = 10;
/**
+ * AVRCP Controller Profile
+ * @hide
+ */
+ public static final int AVRCP_CONTROLLER = 11;
+
+ /**
+ * Headset Client - HFP HF Role
+ * @hide
+ */
+ public static final int HEADSET_CLIENT = 16;
+
+ /**
* Default priority for devices that we try to auto-connect to and
* and allow incoming connections for the profile
* @hide
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 07db8cc..a45c6b8 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -58,6 +58,7 @@
boolean cancelBondProcess(in BluetoothDevice device);
boolean removeBond(in BluetoothDevice device);
int getBondState(in BluetoothDevice device);
+ boolean isConnected(in BluetoothDevice device);
String getRemoteName(in BluetoothDevice device);
int getRemoteType(in BluetoothDevice device);
diff --git a/core/java/android/bluetooth/IBluetoothA2dpSink.aidl b/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
new file mode 100644
index 0000000..b7c6476
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.bluetooth;
+
+import android.bluetooth.BluetoothAudioConfig;
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * APIs for Bluetooth A2DP sink service
+ *
+ * @hide
+ */
+interface IBluetoothA2dpSink {
+ boolean connect(in BluetoothDevice device);
+ boolean disconnect(in BluetoothDevice device);
+ List<BluetoothDevice> getConnectedDevices();
+ List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+ int getConnectionState(in BluetoothDevice device);
+ BluetoothAudioConfig getAudioConfig(in BluetoothDevice device);
+}
diff --git a/core/java/android/hardware/hdmi/IHdmiCecListener.aidl b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
similarity index 60%
rename from core/java/android/hardware/hdmi/IHdmiCecListener.aidl
rename to core/java/android/bluetooth/IBluetoothAvrcpController.aidl
index d281ce6..f917a50 100644
--- a/core/java/android/hardware/hdmi/IHdmiCecListener.aidl
+++ b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
@@ -14,16 +14,18 @@
* limitations under the License.
*/
-package android.hardware.hdmi;
+package android.bluetooth;
-import android.hardware.hdmi.HdmiCecMessage;
+import android.bluetooth.BluetoothDevice;
/**
- * Interface definition for HdmiCecService to do interprocess communcation.
+ * APIs for Bluetooth AVRCP controller service
*
* @hide
*/
-oneway interface IHdmiCecListener {
- void onMessageReceived(in HdmiCecMessage message);
- void onCableStatusChanged(in boolean connected);
+interface IBluetoothAvrcpController {
+ List<BluetoothDevice> getConnectedDevices();
+ List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+ int getConnectionState(in BluetoothDevice device);
+ void sendPassThroughCmd(in BluetoothDevice device, int keyCode, int keyState);
}
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 00a0750..273d76d 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -35,8 +35,6 @@
void startScan(in int appIf, in boolean isServer);
void startScanWithUuids(in int appIf, in boolean isServer, in ParcelUuid[] ids);
- void startScanWithUuidsScanParam(in int appIf, in boolean isServer,
- in ParcelUuid[] ids, int scanWindow, int scanInterval);
void startScanWithFilters(in int appIf, in boolean isServer,
in ScanSettings settings, in List<ScanFilter> filters);
void stopScan(in int appIf, in boolean isServer);
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index bf9e0a7..2d8eed4 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -22,7 +22,7 @@
* Callback definitions for interacting with BLE / GATT
* @hide
*/
-interface IBluetoothGattCallback {
+oneway interface IBluetoothGattCallback {
void onClientRegistered(in int status, in int clientIf);
void onClientConnectionState(in int status, in int clientIf,
in boolean connected, in String address);
@@ -63,7 +63,7 @@
in int charInstId, in ParcelUuid charUuid,
in byte[] value);
void onReadRemoteRssi(in String address, in int rssi, in int status);
- oneway void onAdvertiseStateChange(in int advertiseState, in int status);
- oneway void onMultiAdvertiseCallback(in int status);
+ void onAdvertiseStateChange(in int advertiseState, in int status);
+ void onMultiAdvertiseCallback(in int status);
void onConfigureMTU(in String address, in int mtu, in int status);
}
diff --git a/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
new file mode 100644
index 0000000..e518b7d
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
@@ -0,0 +1,67 @@
+/*
+ * 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.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadsetClientCall;
+import android.os.Bundle;
+
+/**
+ * API for Bluetooth Headset Client service (HFP HF Role)
+ *
+ * {@hide}
+ */
+interface IBluetoothHeadsetClient {
+ boolean connect(in BluetoothDevice device);
+ boolean disconnect(in BluetoothDevice device);
+
+ boolean acceptIncomingConnect(in BluetoothDevice device);
+ boolean rejectIncomingConnect(in BluetoothDevice device);
+
+ List<BluetoothDevice> getConnectedDevices();
+ List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+ int getConnectionState(in BluetoothDevice device);
+ boolean setPriority(in BluetoothDevice device, int priority);
+ int getPriority(in BluetoothDevice device);
+
+ boolean startVoiceRecognition(in BluetoothDevice device);
+ boolean stopVoiceRecognition(in BluetoothDevice device);
+
+ List<BluetoothHeadsetClientCall> getCurrentCalls(in BluetoothDevice device);
+ Bundle getCurrentAgEvents(in BluetoothDevice device);
+
+ boolean acceptCall(in BluetoothDevice device, int flag);
+ boolean holdCall(in BluetoothDevice device);
+ boolean rejectCall(in BluetoothDevice device);
+ boolean terminateCall(in BluetoothDevice device, int index);
+
+ boolean enterPrivateMode(in BluetoothDevice device, int index);
+ boolean explicitCallTransfer(in BluetoothDevice device);
+
+ boolean redial(in BluetoothDevice device);
+ boolean dial(in BluetoothDevice device, String number);
+ boolean dialMemory(in BluetoothDevice device, int location);
+
+ boolean sendDTMF(in BluetoothDevice device, byte code);
+ boolean getLastVoiceTagNumber(in BluetoothDevice device);
+
+ int getAudioState(in BluetoothDevice device);
+ boolean connectAudio();
+ boolean disconnectAudio();
+
+ Bundle getCurrentAgFeatures(in BluetoothDevice device);
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a040efb..fd19b40 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
+import android.annotation.SystemApi;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
@@ -2034,6 +2035,7 @@
AUDIO_SERVICE,
MEDIA_ROUTER_SERVICE,
TELEPHONY_SERVICE,
+ TELECOMM_SERVICE,
CLIPBOARD_SERVICE,
INPUT_METHOD_SERVICE,
TEXT_SERVICES_MANAGER_SERVICE,
@@ -2058,7 +2060,7 @@
PRINT_SERVICE,
MEDIA_SESSION_SERVICE,
BATTERY_SERVICE,
- TASK_SERVICE,
+ JOB_SCHEDULER_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -2115,8 +2117,8 @@
* <dd> A {@link android.app.DownloadManager} for requesting HTTP downloads
* <dt> {@link #BATTERY_SERVICE} ("batterymanager")
* <dd> A {@link android.os.BatteryManager} for managing battery state
- * <dt> {@link #TASK_SERVICE} ("taskmanager")
- * <dd> A {@link android.app.task.TaskManager} for managing scheduled tasks
+ * <dt> {@link #JOB_SCHEDULER_SERVICE} ("taskmanager")
+ * <dd> A {@link android.app.job.JobScheduler} for managing scheduled tasks
* </dl>
*
* <p>Note: System services obtained via this API may be closely associated with
@@ -2148,8 +2150,6 @@
* @see android.app.SearchManager
* @see #SENSOR_SERVICE
* @see android.hardware.SensorManager
- * @see #HDMI_CEC_SERVICE
- * @see android.hardware.hdmi.HdmiCecManager
* @see #STORAGE_SERVICE
* @see android.os.storage.StorageManager
* @see #VIBRATOR_SERVICE
@@ -2164,6 +2164,8 @@
* @see android.media.MediaRouter
* @see #TELEPHONY_SERVICE
* @see android.telephony.TelephonyManager
+ * @see #TELECOMM_SERVICE
+ * @see android.telecomm.TelecommManager
* @see #INPUT_METHOD_SERVICE
* @see android.view.inputmethod.InputMethodManager
* @see #UI_MODE_SERVICE
@@ -2172,8 +2174,8 @@
* @see android.app.DownloadManager
* @see #BATTERY_SERVICE
* @see android.os.BatteryManager
- * @see #TASK_SERVICE
- * @see android.app.task.TaskManager
+ * @see #JOB_SCHEDULER_SERVICE
+ * @see android.app.job.JobScheduler
*/
public abstract Object getSystemService(@ServiceName @NonNull String name);
@@ -2495,6 +2497,16 @@
/**
* Use with {@link #getSystemService} to retrieve a
+ * {@link android.telecomm.TelecommManager} to manage telecomm-related features
+ * of the device.
+ *
+ * @see #getSystemService
+ * @see android.telecomm.TelecommManager
+ */
+ public static final String TELECOMM_SERVICE = "telecomm";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.text.ClipboardManager} for accessing and modifying
* the contents of the global clipboard.
*
@@ -2637,23 +2649,14 @@
/**
* Use with {@link #getSystemService} to retrieve a
- * {@link android.hardware.hdmi.HdmiCecManager} for controlling and managing
- * HDMI-CEC protocol.
- *
- * @see #getSystemService
- * @see android.hardware.hdmi.HdmiCecManager
- */
- // TODO: Remove this once HdmiControlService is ready.
- public static final String HDMI_CEC_SERVICE = "hdmi_cec";
-
- /**
- * Use with {@link #getSystemService} to retrieve a
* {@link android.hardware.hdmi.HdmiControlManager} for controlling and managing
* HDMI-CEC protocol.
*
* @see #getSystemService
* @see android.hardware.hdmi.HdmiControlManager
+ * @hide
*/
+ @SystemApi
public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
/**
@@ -2779,12 +2782,12 @@
/**
* Use with {@link #getSystemService} to retrieve a {@link
- * android.app.task.TaskManager} instance for managing occasional
+ * android.app.job.JobScheduler} instance for managing occasional
* background tasks.
* @see #getSystemService
- * @see android.app.task.TaskManager
+ * @see android.app.job.JobScheduler
*/
- public static final String TASK_SERVICE = "task";
+ public static final String JOB_SCHEDULER_SERVICE = "jobscheduler";
/**
* Determine whether the given permission is allowed for a particular
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index bd07470..6e53a6fb 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2656,7 +2656,9 @@
/**
* Broadcast sent to the primary user when an associated managed profile is added (the profile
* was created and is ready to be used). Carries an extra {@link #EXTRA_USER} that specifies
- * the UserHandle of the profile that was added. This is only sent to registered receivers,
+ * the UserHandle of the profile that was added. Only applications (for example Launchers)
+ * that need to display merged content across both primary and managed profiles need to
+ * worry about this broadcast. This is only sent to registered receivers,
* not manifest receivers.
*/
public static final String ACTION_MANAGED_PROFILE_ADDED =
@@ -2664,8 +2666,10 @@
/**
* Broadcast sent to the primary user when an associated managed profile is removed. Carries an
- * extra {@link #EXTRA_USER} that specifies the UserHandle of the profile that was removed. This
- * is only sent to registered receivers, not manifest receivers.
+ * extra {@link #EXTRA_USER} that specifies the UserHandle of the profile that was removed.
+ * Only applications (for example Launchers) that need to display merged content across both
+ * primary and managed profiles need to worry about this broadcast. This is only sent to
+ * registered receivers, not manifest receivers.
*/
public static final String ACTION_MANAGED_PROFILE_REMOVED =
"android.intent.action.MANAGED_PROFILE_REMOVED";
@@ -2731,6 +2735,7 @@
* returned in {@link #getClipData()}.
*
* @see DocumentsContract
+ * @see #ACTION_OPEN_DOCUMENT_TREE
* @see #ACTION_CREATE_DOCUMENT
* @see #FLAG_GRANT_PERSISTABLE_URI_PERMISSION
*/
@@ -2765,28 +2770,30 @@
*
* @see DocumentsContract
* @see #ACTION_OPEN_DOCUMENT
+ * @see #ACTION_OPEN_DOCUMENT_TREE
* @see #FLAG_GRANT_PERSISTABLE_URI_PERMISSION
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
/**
- * Activity Action: Allow the user to pick a directory. When invoked, the
- * system will display the various {@link DocumentsProvider} instances
- * installed on the device, letting the user navigate through them. Apps can
- * fully manage documents within the returned directory.
+ * Activity Action: Allow the user to pick a directory subtree. When
+ * invoked, the system will display the various {@link DocumentsProvider}
+ * instances installed on the device, letting the user navigate through
+ * them. Apps can fully manage documents within the returned directory.
* <p>
* To gain access to descendant (child, grandchild, etc) documents, use
- * {@link DocumentsContract#buildDocumentViaUri(Uri, String)} and
- * {@link DocumentsContract#buildChildDocumentsViaUri(Uri, String)} using
- * the returned directory URI.
+ * {@link DocumentsContract#buildDocumentUriUsingTree(Uri, String)} and
+ * {@link DocumentsContract#buildChildDocumentsUriUsingTree(Uri, String)}
+ * with the returned URI.
* <p>
- * Output: The URI representing the selected directory.
+ * Output: The URI representing the selected directory tree.
*
* @see DocumentsContract
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_PICK_DIRECTORY = "android.intent.action.PICK_DIRECTORY";
+ public static final String
+ ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
@@ -2976,14 +2983,6 @@
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_CAR_MODE = "android.intent.category.CAR_MODE";
- /**
- * An activity that provides a user interface for adjusting notification preferences for its
- * containing application. Optional but recommended for apps that post
- * {@link android.app.Notification Notifications}.
- */
- @SdkConstant(SdkConstantType.INTENT_CATEGORY)
- public static final String CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
-
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Application launch intent categories (see addCategory()).
@@ -3373,8 +3372,8 @@
*
* @see #ACTION_GET_CONTENT
* @see #ACTION_OPEN_DOCUMENT
+ * @see #ACTION_OPEN_DOCUMENT_TREE
* @see #ACTION_CREATE_DOCUMENT
- * @see #ACTION_PICK_DIRECTORY
*/
public static final String EXTRA_LOCAL_ONLY =
"android.intent.extra.LOCAL_ONLY";
@@ -3712,30 +3711,8 @@
*/
public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 0x00100000;
/**
- * If set, this marks a point in the task's activity stack that should
- * be cleared when the task is reset. That is, the next time the task
- * is brought to the foreground with
- * {@link #FLAG_ACTIVITY_RESET_TASK_IF_NEEDED} (typically as a result of
- * the user re-launching it from home), this activity and all on top of
- * it will be finished so that the user does not return to them, but
- * instead returns to whatever activity preceeded it.
- *
- * <p>When this flag is assigned to the root activity all activities up
- * to, but not including the root activity, will be cleared. This prevents
- * this flag from being used to finish all activities in a task and thereby
- * ending the task.
- *
- * <p>This is useful for cases where you have a logical break in your
- * application. For example, an e-mail application may have a command
- * to view an attachment, which launches an image view activity to
- * display it. This activity should be part of the e-mail application's
- * task, since it is a part of the task the user is involved in. However,
- * if the user leaves that task, and later selects the e-mail app from
- * home, we may like them to return to the conversation they were
- * viewing, not the picture attachment, since that is confusing. By
- * setting this flag when launching the image viewer, that viewer and
- * any activities it starts will be removed the next time the user returns
- * to mail.
+ * @deprecated As of API 21 this performs identically to
+ * {@link #FLAG_ACTIVITY_NEW_DOCUMENT} which should be used instead of this.
*/
public static final int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 0x00080000;
/**
@@ -3762,8 +3739,7 @@
* @see android.R.attr#documentLaunchMode
* @see #FLAG_ACTIVITY_MULTIPLE_TASK
*/
- public static final int FLAG_ACTIVITY_NEW_DOCUMENT =
- FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | FLAG_ACTIVITY_NEW_TASK;
+ public static final int FLAG_ACTIVITY_NEW_DOCUMENT = FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET;
/**
* If set, this flag will prevent the normal {@link android.app.Activity#onUserLeaveHint}
* callback from occurring on the current frontmost activity before it is
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index 869f85c..7619c6d 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -21,6 +21,11 @@
import android.os.Parcel;
import android.os.Parcelable;
+/**
+ * Convenience class to construct sync requests. See {@link android.content.SyncRequest.Builder}
+ * for an explanation of the various functions. The resulting object is passed through to the
+ * framework via {@link android.content.ContentResolver#requestSync(SyncRequest)}.
+ */
public class SyncRequest implements Parcelable {
private static final String TAG = "SyncRequest";
/** Account to pass to the sync adapter. Can be null. */
@@ -57,6 +62,10 @@
return mIsPeriodic;
}
+ /**
+ * {@hide}
+ * @return whether this sync is expedited.
+ */
public boolean isExpedited() {
return mIsExpedited;
}
@@ -199,14 +208,8 @@
* discriminate between equivalent syncs.
*/
private Bundle mSyncConfigExtras;
- /** Expected upload transfer in bytes. */
- private long mTxBytes = -1L;
- /** Expected download transfer in bytes. */
- private long mRxBytes = -1L;
/** Whether or not this sync can occur on metered networks. Default false. */
private boolean mDisallowMetered;
- /** Priority of this sync relative to others from calling app [-2, 2]. Default 0. */
- private int mPriority = 0;
/**
* Whether this builder is building a periodic sync, or a one-time sync.
*/
@@ -314,7 +317,6 @@
return this;
}
- /** {@hide} */
private void setupInterval(long at, long before) {
if (before > at) {
throw new IllegalArgumentException("Specified run time for the sync must be" +
@@ -477,18 +479,6 @@
}
/**
- * @param priority the priority of this request among all requests from the calling app.
- * Range of [-2,2] similar to how this is done with notifications.
- */
- public Builder setPriority(int priority) {
- if (priority < -2 || priority > 2) {
- throw new IllegalArgumentException("Priority must be within range [-2, 2]");
- }
- mPriority = priority;
- return this;
- }
-
- /**
* Performs validation over the request and throws the runtime exception
* <code>IllegalArgumentException</code> if this validation fails.
*
@@ -522,9 +512,6 @@
mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
mSyncConfigExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
}
- mSyncConfigExtras.putLong(ContentResolver.SYNC_EXTRAS_EXPECTED_UPLOAD, mTxBytes);
- mSyncConfigExtras.putLong(ContentResolver.SYNC_EXTRAS_EXPECTED_DOWNLOAD, mRxBytes);
- mSyncConfigExtras.putInt(ContentResolver.SYNC_EXTRAS_PRIORITY, mPriority);
if (mSyncType == SYNC_TYPE_PERIODIC) {
// If this is a periodic sync ensure than invalid extras were not set.
if (ContentResolver.invalidPeriodicExtras(mCustomExtras) ||
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index c2fe3a2..791e5aa 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -84,6 +84,11 @@
*/
public static final int DOCUMENT_LAUNCH_ALWAYS = 2;
/**
+ * Constant corresponding to <code>never</code> in
+ * the {@link android.R.attr#documentLaunchMode} attribute.
+ */
+ public static final int DOCUMENT_LAUNCH_NEVER = 3;
+ /**
* The document launch mode style requested by the activity. From the
* {@link android.R.attr#documentLaunchMode} attribute, one of
* {@link #DOCUMENT_LAUNCH_NONE}, {@link #DOCUMENT_LAUNCH_INTO_EXISTING},
@@ -99,6 +104,12 @@
public int documentLaunchMode;
/**
+ * The maximum number of tasks rooted at this activity that can be in the recent task list.
+ * Refer to {@link android.R.attr#maxRecents}.
+ */
+ public int maxRecents;
+
+ /**
* Optional name of a permission required to be able to access this
* Activity. From the "permission" attribute.
*/
diff --git a/core/java/android/content/pm/ContainerEncryptionParams.java b/core/java/android/content/pm/ContainerEncryptionParams.java
index dd1332b..ab3aa27 100644
--- a/core/java/android/content/pm/ContainerEncryptionParams.java
+++ b/core/java/android/content/pm/ContainerEncryptionParams.java
@@ -16,7 +16,7 @@
package android.content.pm;
-import android.annotation.PrivateApi;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -35,7 +35,7 @@
* @deprecated encrypted containers are legacy.
* @hide
*/
-@PrivateApi
+@SystemApi
@Deprecated
public class ContainerEncryptionParams implements Parcelable {
protected static final String TAG = "ContainerEncryptionParams";
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 04c0b9f..69fa408 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -67,7 +67,6 @@
*
* @param user The UserHandle of the profile that generated the change.
* @param packageName The name of the package that was removed.
- * @hide remove before ship
*/
void onPackageRemoved(UserHandle user, String packageName);
@@ -76,7 +75,6 @@
*
* @param user The UserHandle of the profile that generated the change.
* @param packageName The name of the package that was added.
- * @hide remove before ship
*/
void onPackageAdded(UserHandle user, String packageName);
@@ -85,7 +83,6 @@
*
* @param user The UserHandle of the profile that generated the change.
* @param packageName The name of the package that has changed.
- * @hide remove before ship
*/
void onPackageChanged(UserHandle user, String packageName);
@@ -99,7 +96,6 @@
* available.
* @param replacing Indicates whether these packages are replacing
* existing ones.
- * @hide remove before ship
*/
void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing);
@@ -113,59 +109,9 @@
* unavailable.
* @param replacing Indicates whether the packages are about to be
* replaced with new versions.
- * @hide remove before ship
*/
void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing);
- /**
- * Indicates that a package was removed from the specified profile.
- *
- * @param packageName The name of the package that was removed.
- * @param user The UserHandle of the profile that generated the change.
- */
- void onPackageRemoved(String packageName, UserHandle user);
-
- /**
- * Indicates that a package was added to the specified profile.
- *
- * @param packageName The name of the package that was added.
- * @param user The UserHandle of the profile that generated the change.
- */
- void onPackageAdded(String packageName, UserHandle user);
-
- /**
- * Indicates that a package was modified in the specified profile.
- *
- * @param packageName The name of the package that has changed.
- * @param user The UserHandle of the profile that generated the change.
- */
- void onPackageChanged(String packageName, UserHandle user);
-
- /**
- * Indicates that one or more packages have become available. For
- * example, this can happen when a removable storage card has
- * reappeared.
- *
- * @param packageNames The names of the packages that have become
- * available.
- * @param user The UserHandle of the profile that generated the change.
- * @param replacing Indicates whether these packages are replacing
- * existing ones.
- */
- void onPackagesAvailable(String [] packageNames, UserHandle user, boolean replacing);
-
- /**
- * Indicates that one or more packages have become unavailable. For
- * example, this can happen when a removable storage card has been
- * removed.
- *
- * @param packageNames The names of the packages that have become
- * unavailable.
- * @param user The UserHandle of the profile that generated the change.
- * @param replacing Indicates whether the packages are about to be
- * replaced with new versions.
- */
- void onPackagesUnavailable(String[] packageNames, UserHandle user, boolean replacing);
}
/** @hide */
@@ -361,8 +307,7 @@
}
synchronized (LauncherApps.this) {
for (OnAppsChangedListener listener : mListeners) {
- listener.onPackageRemoved(user, packageName); // TODO: Remove before ship
- listener.onPackageRemoved(packageName, user);
+ listener.onPackageRemoved(user, packageName);
}
}
}
@@ -374,8 +319,7 @@
}
synchronized (LauncherApps.this) {
for (OnAppsChangedListener listener : mListeners) {
- listener.onPackageChanged(user, packageName); // TODO: Remove before ship
- listener.onPackageChanged(packageName, user);
+ listener.onPackageChanged(user, packageName);
}
}
}
@@ -387,8 +331,7 @@
}
synchronized (LauncherApps.this) {
for (OnAppsChangedListener listener : mListeners) {
- listener.onPackageAdded(user, packageName); // TODO: Remove before ship
- listener.onPackageAdded(packageName, user);
+ listener.onPackageAdded(user, packageName);
}
}
}
@@ -401,8 +344,7 @@
}
synchronized (LauncherApps.this) {
for (OnAppsChangedListener listener : mListeners) {
- listener.onPackagesAvailable(user, packageNames, replacing); // TODO: Remove
- listener.onPackagesAvailable(packageNames, user, replacing);
+ listener.onPackagesAvailable(user, packageNames, replacing);
}
}
}
@@ -415,8 +357,7 @@
}
synchronized (LauncherApps.this) {
for (OnAppsChangedListener listener : mListeners) {
- listener.onPackagesUnavailable(user, packageNames, replacing); // TODO: Remove
- listener.onPackagesUnavailable(packageNames, user, replacing);
+ listener.onPackagesUnavailable(user, packageNames, replacing);
}
}
}
diff --git a/core/java/android/content/pm/ManifestDigest.java b/core/java/android/content/pm/ManifestDigest.java
index 943534f..1fbef7a 100644
--- a/core/java/android/content/pm/ManifestDigest.java
+++ b/core/java/android/content/pm/ManifestDigest.java
@@ -16,7 +16,7 @@
package android.content.pm;
-import android.annotation.PrivateApi;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Slog;
@@ -37,7 +37,7 @@
*
* @hide
*/
-@PrivateApi
+@SystemApi
public class ManifestDigest implements Parcelable {
private static final String TAG = "ManifestDigest";
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a34a1b6..8d9b8d9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -17,7 +17,7 @@
package android.content.pm;
import android.annotation.IntDef;
-import android.annotation.PrivateApi;
+import android.annotation.SystemApi;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.PackageInstallObserver;
@@ -26,6 +26,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
+import android.content.pm.PackageParser.PackageParserException;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
@@ -370,7 +371,7 @@
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} on success.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_SUCCEEDED = 1;
/**
@@ -379,7 +380,7 @@
* already installed.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_ALREADY_EXISTS = -1;
/**
@@ -388,7 +389,7 @@
* file is invalid.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_INVALID_APK = -2;
/**
@@ -397,7 +398,7 @@
* is invalid.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_INVALID_URI = -3;
/**
@@ -406,7 +407,7 @@
* service found that the device didn't have enough storage space to install the app.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4;
/**
@@ -415,7 +416,7 @@
* package is already installed with the same name.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_DUPLICATE_PACKAGE = -5;
/**
@@ -424,7 +425,7 @@
* the requested shared user does not exist.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_NO_SHARED_USER = -6;
/**
@@ -434,7 +435,7 @@
* than the new package (and the old package's data was not removed).
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7;
/**
@@ -444,7 +445,7 @@
* device and does not have matching signature.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8;
/**
@@ -453,7 +454,7 @@
* the new package uses a shared library that is not available.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_MISSING_SHARED_LIBRARY = -9;
/**
@@ -462,7 +463,7 @@
* the new package uses a shared library that is not available.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10;
/**
@@ -472,7 +473,7 @@
* either because there was not enough storage or the validation failed.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_DEXOPT = -11;
/**
@@ -482,7 +483,7 @@
* that required by the package.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_OLDER_SDK = -12;
/**
@@ -492,7 +493,7 @@
* same authority as a provider already installed in the system.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13;
/**
@@ -502,7 +503,7 @@
* that required by the package.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_NEWER_SDK = -14;
/**
@@ -513,7 +514,7 @@
* flag.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_TEST_ONLY = -15;
/**
@@ -523,7 +524,7 @@
* compatible with the device's CPU_ABI.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16;
/**
@@ -532,7 +533,7 @@
* the new package uses a feature that is not available.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_MISSING_FEATURE = -17;
// ------ Errors related to sdcard
@@ -542,7 +543,7 @@
* a secure container mount point couldn't be accessed on external media.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_CONTAINER_ERROR = -18;
/**
@@ -552,7 +553,7 @@
* location.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19;
/**
@@ -562,7 +563,7 @@
* location because the media is not available.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20;
/**
@@ -571,7 +572,7 @@
* the new package couldn't be installed because the verification timed out.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_VERIFICATION_TIMEOUT = -21;
/**
@@ -580,7 +581,7 @@
* the new package couldn't be installed because the verification did not succeed.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_VERIFICATION_FAILURE = -22;
/**
@@ -589,7 +590,7 @@
* the package changed from what the calling program expected.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23;
/**
@@ -615,7 +616,7 @@
* '.apk' extension.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_PARSE_FAILED_NOT_APK = -100;
/**
@@ -624,7 +625,7 @@
* if the parser was unable to retrieve the AndroidManifest.xml file.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_PARSE_FAILED_BAD_MANIFEST = -101;
/**
@@ -633,7 +634,7 @@
* if the parser encountered an unexpected exception.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102;
/**
@@ -642,7 +643,7 @@
* if the parser did not find any certificates in the .apk.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103;
/**
@@ -651,7 +652,7 @@
* if the parser found inconsistent certificates on the files in the .apk.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES = -104;
/**
@@ -661,7 +662,7 @@
* files in the .apk.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING = -105;
/**
@@ -670,7 +671,7 @@
* if the parser encountered a bad or missing package name in the manifest.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106;
/**
@@ -679,7 +680,7 @@
* if the parser encountered a bad shared user id name in the manifest.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID = -107;
/**
@@ -688,7 +689,7 @@
* if the parser encountered some structural problem in the manifest.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_PARSE_FAILED_MANIFEST_MALFORMED = -108;
/**
@@ -698,7 +699,7 @@
* in the manifest.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109;
/**
@@ -707,7 +708,7 @@
* if the system failed to install the package because of system issues.
* @hide
*/
- @PrivateApi
+ @SystemApi
public static final int INSTALL_FAILED_INTERNAL_ERROR = -110;
/**
@@ -2873,16 +2874,17 @@
DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
final File sourceFile = new File(archiveFilePath);
- PackageParser.Package pkg = packageParser.parsePackage(
- sourceFile, archiveFilePath, metrics, 0);
- if (pkg == null) {
+ try {
+ PackageParser.Package pkg = packageParser.parseMonolithicPackage(sourceFile, metrics,
+ 0);
+ if ((flags & GET_SIGNATURES) != 0) {
+ packageParser.collectCertificates(pkg, 0);
+ }
+ PackageUserState state = new PackageUserState();
+ return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
+ } catch (PackageParserException e) {
return null;
}
- if ((flags & GET_SIGNATURES) != 0) {
- packageParser.collectCertificates(pkg, 0);
- }
- PackageUserState state = new PackageUserState();
- return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
}
/**
@@ -2907,7 +2909,7 @@
* instead. This method will continue to be supported but the older observer interface
* will not get additional failure details.
*/
- // @PrivateApi
+ // @SystemApi
public abstract void installPackage(
Uri packageURI, IPackageInstallObserver observer, int flags,
String installerPackageName);
@@ -2942,7 +2944,7 @@
* continue to be supported but the older observer interface will not get additional failure
* details.
*/
- // @PrivateApi
+ // @SystemApi
public abstract void installPackageWithVerification(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
Uri verificationURI, ManifestDigest manifestDigest,
@@ -3071,7 +3073,7 @@
* on the system for other users, also install it for the calling user.
* @hide
*/
- // @PrivateApi
+ // @SystemApi
public abstract int installExistingPackage(String packageName)
throws NameNotFoundException;
@@ -3161,7 +3163,7 @@
*
* @hide
*/
- // @PrivateApi
+ // @SystemApi
public abstract void deletePackage(
String packageName, IPackageDeleteObserver observer, int flags);
@@ -3230,7 +3232,7 @@
*
* @hide
*/
- // @PrivateApi
+ // @SystemApi
public abstract void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer);
/**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ab8bf61..91895ff 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -18,6 +18,7 @@
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
import android.content.ComponentName;
import android.content.Intent;
@@ -31,6 +32,7 @@
import android.os.Bundle;
import android.os.PatternMatcher;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Base64;
import android.util.DisplayMetrics;
@@ -81,6 +83,8 @@
private static final boolean DEBUG_PARSER = false;
private static final boolean DEBUG_BACKUP = false;
+ // TODO: switch outError users to PackageParserException
+
/** File name in an APK for the Android manifest. */
private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
@@ -207,10 +211,10 @@
}
}
- /* Light weight package info.
- * @hide
+ /**
+ * Lightweight parsed details about a single APK file.
*/
- public static class PackageLite {
+ public static class ApkLite {
public final String packageName;
public final String splitName;
public final int versionCode;
@@ -218,7 +222,7 @@
public final VerifierInfo[] verifiers;
public final Signature[] signatures;
- public PackageLite(String packageName, String splitName, int versionCode,
+ public ApkLite(String packageName, String splitName, int versionCode,
int installLocation, List<VerifierInfo> verifiers, Signature[] signatures) {
this.packageName = packageName;
this.splitName = splitName;
@@ -247,6 +251,10 @@
mArchiveSourcePath = archiveSourcePath;
}
+ public PackageParser(File archiveSource) {
+ this(archiveSource.getAbsolutePath());
+ }
+
public void setSeparateProcesses(String[] procs) {
mSeparateProcesses = procs;
}
@@ -255,6 +263,10 @@
mOnlyCoreApps = onlyCoreApps;
}
+ private static final boolean isPackageFilename(File file) {
+ return isPackageFilename(file.getName());
+ }
+
private static final boolean isPackageFilename(String name) {
return name.endsWith(".apk");
}
@@ -497,26 +509,84 @@
public final static int PARSE_IS_PRIVILEGED = 1<<7;
public final static int PARSE_GET_SIGNATURES = 1<<8;
- public int getParseError() {
- return mParseError;
+ /**
+ * Parse all APK files under the given directory as a single package.
+ */
+ public Package parseSplitPackage(File apkDir, DisplayMetrics metrics, int flags,
+ boolean trustedOverlay) throws PackageParserException {
+ final File[] files = apkDir.listFiles();
+ if (ArrayUtils.isEmpty(files)) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "No packages found in split");
+ }
+
+ File baseFile = null;
+ for (File file : files) {
+ if (file.isFile() && isPackageFilename(file)) {
+ ApkLite lite = parseApkLite(file.getAbsolutePath(), 0);
+ if (lite == null) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Invalid package file: " + file);
+ }
+
+ if (TextUtils.isEmpty(lite.splitName)) {
+ baseFile = file;
+ break;
+ }
+ }
+ }
+
+ if (baseFile == null) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Missing base APK in " + apkDir);
+ }
+
+ final Package pkg = parseBaseApk(baseFile, metrics, flags, trustedOverlay);
+ if (pkg == null) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Failed to parse base APK: " + baseFile);
+ }
+
+ for (File file : files) {
+ if (file.isFile() && isPackageFilename(file) && !file.equals(baseFile)) {
+ parseSplitApk(pkg, file, metrics, flags, trustedOverlay);
+ }
+ }
+
+ // Always use a well-defined sort order
+ if (pkg.splitCodePaths != null) {
+ Arrays.sort(pkg.splitCodePaths);
+ }
+
+ return pkg;
}
- public Package parsePackage(File sourceFile, String destCodePath,
- DisplayMetrics metrics, int flags) {
- return parsePackage(sourceFile, destCodePath, metrics, flags, false);
+ public Package parseMonolithicPackage(File apkFile, DisplayMetrics metrics, int flags)
+ throws PackageParserException {
+ return parseMonolithicPackage(apkFile, metrics, flags, false);
}
- public Package parsePackage(File sourceFile, String destCodePath,
- DisplayMetrics metrics, int flags, boolean trustedOverlay) {
+ public Package parseMonolithicPackage(File apkFile, DisplayMetrics metrics, int flags,
+ boolean trustedOverlay) throws PackageParserException {
+ final Package pkg = parseBaseApk(apkFile, metrics, flags, trustedOverlay);
+ if (pkg != null) {
+ return pkg;
+ } else {
+ throw new PackageParserException(mParseError, "Failed to parse " + apkFile);
+ }
+ }
+
+ private Package parseBaseApk(File apkFile, DisplayMetrics metrics, int flags,
+ boolean trustedOverlay) {
mParseError = PackageManager.INSTALL_SUCCEEDED;
- mArchiveSourcePath = sourceFile.getPath();
- if (!sourceFile.isFile()) {
+ mArchiveSourcePath = apkFile.getAbsolutePath();
+ if (!apkFile.isFile()) {
Slog.w(TAG, "Skipping dir: " + mArchiveSourcePath);
mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
return null;
}
- if (!isPackageFilename(sourceFile.getName())
+ if (!isPackageFilename(apkFile.getName())
&& (flags&PARSE_MUST_BE_APK) != 0) {
if ((flags&PARSE_IS_SYSTEM) == 0) {
// We expect to have non-.apk files in the system dir,
@@ -560,13 +630,12 @@
Exception errorException = null;
try {
// XXXX todo: need to figure out correct configuration.
- pkg = parsePackage(res, parser, flags, trustedOverlay, errorText);
+ pkg = parseBaseApk(res, parser, flags, trustedOverlay, errorText);
} catch (Exception e) {
errorException = e;
mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
}
-
if (pkg == null) {
// If we are only parsing core apps, then a null with INSTALL_SUCCEEDED
// just means to skip this app so don't make a fuss about it.
@@ -590,22 +659,25 @@
parser.close();
assmgr.close();
- // Set code and resource paths
- pkg.mPath = destCodePath;
- pkg.mScanPath = mArchiveSourcePath;
- //pkg.applicationInfo.sourceDir = destCodePath;
- //pkg.applicationInfo.publicSourceDir = destRes;
+ pkg.codePath = mArchiveSourcePath;
pkg.mSignatures = null;
return pkg;
}
+ private void parseSplitApk(Package pkg, File apkFile, DisplayMetrics metrics, int flags,
+ boolean trustedOverlay) throws PackageParserException {
+ // TODO: expand split APK parsing
+ pkg.splitCodePaths = ArrayUtils.appendElement(String.class, pkg.splitCodePaths,
+ apkFile.getAbsolutePath());
+ }
+
/**
* Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the
* APK. If it successfully scanned the package and found the
* {@code AndroidManifest.xml}, {@code true} is returned.
*/
- public boolean collectManifestDigest(Package pkg) {
+ public void collectManifestDigest(Package pkg) throws PackageParserException {
try {
final StrictJarFile jarFile = new StrictJarFile(mArchiveSourcePath);
try {
@@ -616,13 +688,19 @@
} finally {
jarFile.close();
}
- return true;
} catch (IOException e) {
- return false;
+ throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Failed to collect manifest digest");
}
}
- public boolean collectCertificates(Package pkg, int flags) {
+ public void collectCertificates(Package pkg, int flags) throws PackageParserException {
+ if (!collectCertificatesInternal(pkg, flags)) {
+ throw new PackageParserException(mParseError, "Failed to collect certificates");
+ }
+ }
+
+ private boolean collectCertificatesInternal(Package pkg, int flags) {
pkg.mSignatures = null;
WeakReference<byte[]> readBufferRef;
@@ -808,7 +886,7 @@
* @param flags Special parse flags
* @return PackageLite object with package information or null on failure.
*/
- public static PackageLite parsePackageLite(String packageFilePath, int flags) {
+ public static ApkLite parseApkLite(String packageFilePath, int flags) {
AssetManager assmgr = null;
final XmlResourceParser parser;
final Resources res;
@@ -844,9 +922,9 @@
final AttributeSet attrs = parser;
final String errors[] = new String[1];
- PackageLite packageLite = null;
+ ApkLite packageLite = null;
try {
- packageLite = parsePackageLite(res, parser, attrs, flags, signatures, errors);
+ packageLite = parseApkLite(res, parser, attrs, flags, signatures, errors);
} catch (PackageParserException e) {
Slog.w(TAG, packageFilePath, e);
} catch (IOException e) {
@@ -930,7 +1008,7 @@
(splitName != null) ? splitName.intern() : splitName);
}
- private static PackageLite parsePackageLite(Resources res, XmlPullParser parser,
+ private static ApkLite parseApkLite(Resources res, XmlPullParser parser,
AttributeSet attrs, int flags, Signature[] signatures, String[] outError)
throws IOException, XmlPullParserException, PackageParserException {
final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags);
@@ -972,7 +1050,7 @@
}
}
- return new PackageLite(packageSplit.first, packageSplit.second, versionCode,
+ return new ApkLite(packageSplit.first, packageSplit.second, versionCode,
installLocation, verifiers, signatures);
}
@@ -988,9 +1066,8 @@
return new Signature(sig);
}
- private Package parsePackage(
- Resources res, XmlResourceParser parser, int flags, boolean trustedOverlay,
- String[] outError) throws XmlPullParserException, IOException {
+ private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
+ boolean trustedOverlay, String[] outError) throws XmlPullParserException, IOException {
AttributeSet attrs = parser;
mParseInstrumentationArgs = null;
@@ -1019,7 +1096,13 @@
}
}
- final Package pkg = new Package(pkgName, splitName);
+ if (!TextUtils.isEmpty(splitName)) {
+ outError[0] = "Expected base APK, but found split " + splitName;
+ mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
+ return null;
+ }
+
+ final Package pkg = new Package(pkgName);
boolean foundApp = false;
TypedArray sa = res.obtainAttributes(attrs,
@@ -2511,6 +2594,9 @@
a.info.documentLaunchMode = sa.getInt(
com.android.internal.R.styleable.AndroidManifestActivity_documentLaunchMode,
ActivityInfo.DOCUMENT_LAUNCH_NONE);
+ a.info.maxRecents = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestActivity_maxRecents,
+ 15);
a.info.screenOrientation = sa.getInt(
com.android.internal.R.styleable.AndroidManifestActivity_screenOrientation,
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
@@ -3577,10 +3663,17 @@
return true;
}
+ /**
+ * Representation of a full package parsed from APK files on disk. A package
+ * consists of a single base APK, and zero or more split APKs.
+ */
public final static class Package {
public String packageName;
- public String splitName;
+
+ // TODO: work towards making these paths invariant
+ public String codePath;
+ public String[] splitCodePaths;
// For now we only support one application per package.
public final ApplicationInfo applicationInfo = new ApplicationInfo();
@@ -3612,9 +3705,6 @@
// We store the application meta-data independently to avoid multiple unwanted references
public Bundle mAppMetaData = null;
- // If this is a 3rd party app, this is the path of the zip file.
- public String mPath;
-
// The version code declared for this package.
public int mVersionCode;
@@ -3634,10 +3724,6 @@
// preferred up order.
public int mPreferredOrder = 0;
- // For use by the package manager to keep track of the path to the
- // file an app came from.
- public String mScanPath;
-
// For use by package manager to keep track of where it needs to do dexopt.
public boolean mDexOptNeeded = true;
@@ -3697,9 +3783,8 @@
public Set<PublicKey> mSigningKeys;
public Map<String, Set<PublicKey>> mKeySetMapping;
- public Package(String packageName, String splitName) {
+ public Package(String packageName) {
this.packageName = packageName;
- this.splitName = splitName;
applicationInfo.packageName = packageName;
applicationInfo.uid = -1;
}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index a07fc97..a83bd4a 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -17,11 +17,14 @@
package android.content.res;
import android.content.pm.ActivityInfo;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.view.View;
+import java.text.Format;
+import java.util.ArrayList;
import java.util.Locale;
/**
@@ -1306,4 +1309,240 @@
private static int getScreenLayoutNoDirection(int screenLayout) {
return screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK;
}
+
+ /**
+ *
+ * @hide
+ */
+ public static String localeToResourceQualifier(Locale locale) {
+ StringBuilder sb = new StringBuilder();
+ boolean l = (locale.getLanguage().length() != 0);
+ boolean c = (locale.getCountry().length() != 0);
+ boolean s = (locale.getScript().length() != 0);
+ boolean v = (locale.getVariant().length() != 0);
+
+ if (l) {
+ sb.append(locale.getLanguage());
+ if (c) {
+ sb.append("-r").append(locale.getCountry());
+ if (s) {
+ sb.append("-s").append(locale.getScript());
+ if (v) {
+ sb.append("-v").append(locale.getVariant());
+ }
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+
+ /**
+ * Returns a string representation of the configuration that can be parsed
+ * by build tools (like AAPT).
+ *
+ *
+ *
+ * @hide
+ */
+ public static String resourceQualifierString(Configuration config) {
+ ArrayList<String> parts = new ArrayList<String>();
+
+ if (config.mcc != 0) {
+ parts.add(config.mcc + "mcc");
+ if (config.mnc != 0) {
+ parts.add(config.mnc + "mnc");
+ }
+ }
+
+ if (!config.locale.getLanguage().isEmpty()) {
+ parts.add(localeToResourceQualifier(config.locale));
+ }
+
+ switch (config.screenLayout & Configuration.SCREENLAYOUT_LAYOUTDIR_MASK) {
+ case Configuration.SCREENLAYOUT_LAYOUTDIR_LTR:
+ parts.add("ldltr");
+ break;
+ case Configuration.SCREENLAYOUT_LAYOUTDIR_RTL:
+ parts.add("ldrtl");
+ break;
+ default:
+ break;
+ }
+
+ if (config.smallestScreenWidthDp != 0) {
+ parts.add("sw" + config.smallestScreenWidthDp + "dp");
+ }
+
+ if (config.screenWidthDp != 0) {
+ parts.add("w" + config.screenWidthDp + "dp");
+ }
+
+ if (config.screenHeightDp != 0) {
+ parts.add("h" + config.screenHeightDp + "dp");
+ }
+
+ switch (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) {
+ case Configuration.SCREENLAYOUT_SIZE_SMALL:
+ parts.add("small");
+ break;
+ case Configuration.SCREENLAYOUT_SIZE_NORMAL:
+ parts.add("normal");
+ break;
+ case Configuration.SCREENLAYOUT_SIZE_LARGE:
+ parts.add("large");
+ break;
+ case Configuration.SCREENLAYOUT_SIZE_XLARGE:
+ parts.add("xlarge");
+ break;
+ default:
+ break;
+ }
+
+ switch (config.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) {
+ case Configuration.SCREENLAYOUT_LONG_YES:
+ parts.add("long");
+ break;
+ case Configuration.SCREENLAYOUT_LONG_NO:
+ parts.add("notlong");
+ break;
+ default:
+ break;
+ }
+
+ switch (config.orientation) {
+ case Configuration.ORIENTATION_LANDSCAPE:
+ parts.add("land");
+ break;
+ case Configuration.ORIENTATION_PORTRAIT:
+ parts.add("port");
+ break;
+ default:
+ break;
+ }
+
+ switch (config.uiMode & Configuration.UI_MODE_TYPE_MASK) {
+ case Configuration.UI_MODE_TYPE_APPLIANCE:
+ parts.add("appliance");
+ break;
+ case Configuration.UI_MODE_TYPE_DESK:
+ parts.add("desk");
+ break;
+ case Configuration.UI_MODE_TYPE_TELEVISION:
+ parts.add("television");
+ break;
+ case Configuration.UI_MODE_TYPE_CAR:
+ parts.add("car");
+ break;
+ case Configuration.UI_MODE_TYPE_WATCH:
+ parts.add("watch");
+ break;
+ default:
+ break;
+ }
+
+ switch (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) {
+ case Configuration.UI_MODE_NIGHT_YES:
+ parts.add("night");
+ break;
+ case Configuration.UI_MODE_NIGHT_NO:
+ parts.add("notnight");
+ break;
+ default:
+ break;
+ }
+
+ switch (config.densityDpi) {
+ case 0:
+ break;
+ case 120:
+ parts.add("ldpi");
+ break;
+ case 160:
+ parts.add("mdpi");
+ break;
+ case 213:
+ parts.add("tvdpi");
+ break;
+ case 240:
+ parts.add("hdpi");
+ break;
+ case 320:
+ parts.add("xhdpi");
+ break;
+ default:
+ parts.add(config.densityDpi + "dpi");
+ break;
+ }
+
+ switch (config.touchscreen) {
+ case Configuration.TOUCHSCREEN_NOTOUCH:
+ parts.add("notouch");
+ break;
+ case Configuration.TOUCHSCREEN_FINGER:
+ parts.add("finger");
+ break;
+ default:
+ break;
+ }
+
+ switch (config.keyboardHidden) {
+ case Configuration.KEYBOARDHIDDEN_NO:
+ parts.add("keysexposed");
+ break;
+ case Configuration.KEYBOARDHIDDEN_YES:
+ parts.add("keyshidden");
+ break;
+ case Configuration.KEYBOARDHIDDEN_SOFT:
+ parts.add("keyssoft");
+ break;
+ default:
+ break;
+ }
+
+ switch (config.keyboard) {
+ case Configuration.KEYBOARD_NOKEYS:
+ parts.add("nokeys");
+ break;
+ case Configuration.KEYBOARD_QWERTY:
+ parts.add("qwerty");
+ break;
+ case Configuration.KEYBOARD_12KEY:
+ parts.add("12key");
+ break;
+ default:
+ break;
+ }
+
+ switch (config.navigationHidden) {
+ case Configuration.NAVIGATIONHIDDEN_NO:
+ parts.add("navexposed");
+ break;
+ case Configuration.NAVIGATIONHIDDEN_YES:
+ parts.add("navhidden");
+ break;
+ default:
+ break;
+ }
+
+ switch (config.navigation) {
+ case Configuration.NAVIGATION_NONAV:
+ parts.add("nonav");
+ break;
+ case Configuration.NAVIGATION_DPAD:
+ parts.add("dpad");
+ break;
+ case Configuration.NAVIGATION_TRACKBALL:
+ parts.add("trackball");
+ break;
+ case Configuration.NAVIGATION_WHEEL:
+ parts.add("wheel");
+ break;
+ default:
+ break;
+ }
+
+ parts.add("v" + Build.VERSION.SDK_INT);
+ return TextUtils.join("-", parts);
+ }
}
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index c8de2f1..de2cc67 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -708,6 +708,7 @@
* is generated if the direction of the 2-seconds window average gravity changed by at
* least 35 degrees since the activation of the sensor. It is a wake up sensor.
*
+ * @hide
* @see #isWakeUpSensor()
*/
public static final int TYPE_WAKE_UP_TILT_DETECTOR = 41;
@@ -715,6 +716,7 @@
/**
* A constant string describing a wake up tilt detector sensor type.
*
+ * @hide
* @see #TYPE_WAKE_UP_TILT_DETECTOR
*/
public static final String SENSOR_STRING_TYPE_WAKE_UP_TILT_DETECTOR =
@@ -752,16 +754,47 @@
*/
public static final int TYPE_ALL = -1;
- /* Reporting mode constants for sensors. Each sensor will have exactly one
- reporting mode associated with it. */
- // Events are reported at a constant rate.
- static int REPORTING_MODE_CONTINUOUS = 1;
+ // If this flag is set, the sensor defined as a wake up sensor. This field and REPORTING_MODE_*
+ // constants are defined as flags in sensors.h. Modify at both places if needed.
+ private static final int SENSOR_FLAG_WAKE_UP_SENSOR = 1;
- // Events are reported only when the value changes.
- static int REPORTING_MODE_ON_CHANGE = 2;
+ /**
+ * Events are reported at a constant rate which is set by the rate parameter of
+ * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)}. Note: If other
+ * applications are requesting a higher rate, the sensor data might be delivered at faster rates
+ * than requested.
+ */
+ public static final int REPORTING_MODE_CONTINUOUS = 0;
- // Upon detection of an event, the sensor deactivates itself and then sends a single event.
- static int REPORTING_MODE_ONE_SHOT = 3;
+ /**
+ * Events are reported only when the value changes. Event delivery rate can be limited by
+ * setting appropriate value for rate parameter of
+ * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)} Note: If other
+ * applications are requesting a higher rate, the sensor data might be delivered at faster rates
+ * than requested.
+ */
+ public static final int REPORTING_MODE_ON_CHANGE = 1;
+
+ /**
+ * Events are reported in one-shot mode. Upon detection of an event, the sensor deactivates
+ * itself and then sends a single event. Sensors of this reporting mode must be registered to
+ * using {@link SensorManager#requestTriggerSensor(TriggerEventListener, Sensor)}.
+ */
+ public static final int REPORTING_MODE_ONE_SHOT = 2;
+
+ /**
+ * Events are reported as described in the description of the sensor. The rate passed to
+ * registerListener might not have an impact on the rate of event delivery. See the sensor
+ * definition for more information on when and how frequently the events are reported. For
+ * example, step detectors report events when a step is detected.
+ *
+ * @see SensorManager#registerListener(SensorEventListener, Sensor, int, int)
+ */
+ public static final int REPORTING_MODE_SPECIAL_TRIGGER = 3;
+
+ // Mask for the LSB 2nd, 3rd and fourth bits.
+ private static final int REPORTING_MODE_MASK = 0xE;
+ private static final int REPORTING_MODE_SHIFT = 1;
// TODO(): The following arrays are fragile and error-prone. This needs to be refactored.
@@ -770,80 +803,74 @@
// associated with
// {@link SensorEvent} or {@link TriggerEvent} for the Sensor
private static final int[] sSensorReportingModes = {
- 0, 0, // padding because sensor types start at 1
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_ACCELEROMETER
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_GEOMAGNETIC_FIELD
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_ORIENTATION
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_GYROSCOPE
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_LIGHT
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_PRESSURE
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_TEMPERATURE
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_PROXIMITY
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_GRAVITY
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_LINEAR_ACCELERATION
- REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_ROTATION_VECTOR
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_RELATIVE_HUMIDITY
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_AMBIENT_TEMPERATURE
- REPORTING_MODE_CONTINUOUS, 6, // SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED
- REPORTING_MODE_CONTINUOUS, 4, // SENSOR_TYPE_GAME_ROTATION_VECTOR
- REPORTING_MODE_CONTINUOUS, 6, // SENSOR_TYPE_GYROSCOPE_UNCALIBRATED
- REPORTING_MODE_ONE_SHOT, 1, // SENSOR_TYPE_SIGNIFICANT_MOTION
- // added post 4.3
- REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_STEP_DETECTOR
- REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_STEP_COUNTER
- REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
- REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_HEART_RATE_MONITOR
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR
+ 0, // padding because sensor types start at 1
+ 3, // SENSOR_TYPE_ACCELEROMETER
+ 3, // SENSOR_TYPE_GEOMAGNETIC_FIELD
+ 3, // SENSOR_TYPE_ORIENTATION
+ 3, // SENSOR_TYPE_GYROSCOPE
+ 3, // SENSOR_TYPE_LIGHT
+ 3, // SENSOR_TYPE_PRESSURE
+ 3, // SENSOR_TYPE_TEMPERATURE
+ 3, // SENSOR_TYPE_PROXIMITY
+ 3, // SENSOR_TYPE_GRAVITY
+ 3, // SENSOR_TYPE_LINEAR_ACCELERATION
+ 5, // SENSOR_TYPE_ROTATION_VECTOR
+ 3, // SENSOR_TYPE_RELATIVE_HUMIDITY
+ 3, // SENSOR_TYPE_AMBIENT_TEMPERATURE
+ 6, // SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED
+ 4, // SENSOR_TYPE_GAME_ROTATION_VECTOR
+ 6, // SENSOR_TYPE_GYROSCOPE_UNCALIBRATED
+ 1, // SENSOR_TYPE_SIGNIFICANT_MOTION
+ 1, // SENSOR_TYPE_STEP_DETECTOR
+ 1, // SENSOR_TYPE_STEP_COUNTER
+ 5, // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+ 1, // SENSOR_TYPE_HEART_RATE_MONITOR
+ 3, // SENSOR_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR
// wake up variants of base sensors
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_ACCELEROMETER
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_ORIENTATION
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_GYROSCOPE
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_WAKE_UP_LIGHT
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_PRESSURE
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_GRAVITY
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_LINEAR_ACCELERATION
- REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_WAKE_UP_ROTATION_VECTOR
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_WAKE_UP_RELATIVE_HUMIDITY
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_WAKE_UP_AMBIENT_TEMPERATURE
- REPORTING_MODE_CONTINUOUS, 6, // SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED
- REPORTING_MODE_CONTINUOUS, 4, // SENSOR_TYPE_WAKE_UP_GAME_ROTATION_VECTOR
- REPORTING_MODE_CONTINUOUS, 6, // SENSOR_TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED
- REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_WAKE_UP_STEP_DETECTOR
- REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_WAKE_UP_STEP_COUNTER
- REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR
- REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_WAKE_UP_HEART_RATE_MONITOR
- REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_WAKE_UP_TILT_DETECTOR
- REPORTING_MODE_ONE_SHOT, 1, // SENSOR_TYPE_WAKE_GESTURE
+ 3, // SENSOR_TYPE_WAKE_UP_ACCELEROMETER
+ 3, // SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD
+ 3, // SENSOR_TYPE_WAKE_UP_ORIENTATION
+ 3, // SENSOR_TYPE_WAKE_UP_GYROSCOPE
+ 3, // SENSOR_TYPE_WAKE_UP_LIGHT
+ 3, // SENSOR_TYPE_WAKE_UP_PRESSURE
+ 3, // SENSOR_TYPE_WAKE_UP_GRAVITY
+ 3, // SENSOR_TYPE_WAKE_UP_LINEAR_ACCELERATION
+ 5, // SENSOR_TYPE_WAKE_UP_ROTATION_VECTOR
+ 3, // SENSOR_TYPE_WAKE_UP_RELATIVE_HUMIDITY
+ 3, // SENSOR_TYPE_WAKE_UP_AMBIENT_TEMPERATURE
+ 6, // SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED
+ 4, // SENSOR_TYPE_WAKE_UP_GAME_ROTATION_VECTOR
+ 6, // SENSOR_TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED
+ 1, // SENSOR_TYPE_WAKE_UP_STEP_DETECTOR
+ 1, // SENSOR_TYPE_WAKE_UP_STEP_COUNTER
+ 5, // SENSOR_TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR
+ 1, // SENSOR_TYPE_WAKE_UP_HEART_RATE_MONITOR
+ 1, // SENSOR_TYPE_WAKE_UP_TILT_DETECTOR
+ 1, // SENSOR_TYPE_WAKE_GESTURE
};
- static int getReportingMode(Sensor sensor) {
- int offset = sensor.mType * 2;
- if (offset >= sSensorReportingModes.length) {
- // we don't know about this sensor, so this is probably a
- // vendor-defined sensor, in that case, we figure out the reporting
- // mode from the sensor meta-data.
- int minDelay = sensor.mMinDelay;
- if (minDelay == 0) {
- return REPORTING_MODE_ON_CHANGE;
- } else if (minDelay < 0) {
- return REPORTING_MODE_ONE_SHOT;
- } else {
- return REPORTING_MODE_CONTINUOUS;
- }
- }
- return sSensorReportingModes[offset];
+ /**
+ * Each sensor has exactly one reporting mode associated with it. This method returns the
+ * reporting mode constant for this sensor type.
+ *
+ * @return Reporting mode for the input sensor, one of REPORTING_MODE_* constants.
+ * @see #REPORTING_MODE_CONTINUOUS
+ * @see #REPORTING_MODE_ON_CHANGE
+ * @see #REPORTING_MODE_ONE_SHOT
+ * @see #REPORTING_MODE_SPECIAL_TRIGGER
+ */
+ public int getReportingMode() {
+ return ((mFlags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT);
}
static int getMaxLengthValuesArray(Sensor sensor, int sdkLevel) {
- int type = sensor.mType;
// RotationVector length has changed to 3 to 5 for API level 18
// Set it to 3 for backward compatibility.
- if (type == Sensor.TYPE_ROTATION_VECTOR &&
+ if (sensor.mType == Sensor.TYPE_ROTATION_VECTOR &&
sdkLevel <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
return 3;
}
- int offset = type * 2 + 1;
+ int offset = sensor.mType;
if (offset >= sSensorReportingModes.length) {
// we don't know about this sensor, so this is probably a
// vendor-defined sensor, in that case, we don't know how many value
@@ -873,7 +900,7 @@
private String mStringType;
private String mRequiredPermission;
private int mMaxDelay;
- private boolean mWakeUpSensor;
+ private int mFlags;
Sensor() {
}
@@ -1016,7 +1043,7 @@
* @return true if this is a wake up sensor, false otherwise.
*/
public boolean isWakeUpSensor() {
- return mWakeUpSensor;
+ return (mFlags & SENSOR_FLAG_WAKE_UP_SENSOR) != 0;
}
void setRange(float max, float res) {
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index b66ec86..a6c3ea4 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -99,7 +99,7 @@
return false;
}
// Trigger Sensors should use the requestTriggerSensor call.
- if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) {
+ if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
Log.e(TAG, "Trigger Sensors should use the requestTriggerSensor.");
return false;
}
@@ -133,7 +133,7 @@
@Override
protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
// Trigger Sensors should use the cancelTriggerSensor call.
- if (sensor != null && Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) {
+ if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
return;
}
@@ -159,7 +159,7 @@
protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
- if (Sensor.getReportingMode(sensor) != Sensor.REPORTING_MODE_ONE_SHOT) return false;
+ if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false;
synchronized (mTriggerListeners) {
TriggerEventQueue queue = mTriggerListeners.get(listener);
@@ -181,7 +181,7 @@
@Override
protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
boolean disable) {
- if (sensor != null && Sensor.getReportingMode(sensor) != Sensor.REPORTING_MODE_ONE_SHOT) {
+ if (sensor != null && sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) {
return false;
}
synchronized (mTriggerListeners) {
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 5fd0f9b..d98bdc2 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -29,19 +29,19 @@
*
* <p>Creating a session is an expensive operation and can take several hundred milliseconds, since
* it requires configuring the camera device's internal pipelines and allocating memory buffers for
- * sending images to the desired targets. While
- * {@link CameraDevice#createCaptureSession createCaptureSession} will provide a
- * CameraCaptureSession object immediately, configuration won't be complete until the
- * {@link CameraCaptureSession.StateListener#onConfigured onConfigured} callback is called for the
- * first time. If configuration cannot be completed, then the
+ * sending images to the desired targets. Therefore the setup is done asynchronously, and
+ * {@link CameraDevice#createCaptureSession createCaptureSession} will send the ready-to-use
+ * CameraCaptureSession to the provided listener's
+ * {@link CameraCaptureSession.StateListener#onConfigured onConfigured} callback. If configuration
+ * cannot be completed, then the
* {@link CameraCaptureSession.StateListener#onConfigureFailed onConfigureFailed} is called, and the
* session will not become active.</p>
- *
+ *<!--
* <p>Any capture requests (repeating or non-repeating) submitted before the session is ready will
* be queued up and will begin capture once the session becomes ready. In case the session cannot be
* configured and {@link StateListener#onConfigureFailed onConfigureFailed} is called, all queued
* capture requests are discarded.</p>
- *
+ *-->
* <p>If a new session is created by the camera device, then the previous session is closed, and its
* associated {@link StateListener#onClosed onClosed} callback will be invoked. All
* of the session methods will throw an IllegalStateException if called once the session is
@@ -166,10 +166,6 @@
* capture request will be processed before any further repeating
* requests are processed.<p>
*
- * <p>Repeating requests are a simple way for an application to maintain a
- * preview or other continuous stream of frames, without having to submit
- * requests through {@link #capture} at video rates.</p>
- *
* <p>To stop the repeating capture, call {@link #stopRepeating}. Calling
* {@link #abortCaptures} will also clear the request.</p>
*
@@ -323,7 +319,7 @@
*
* @see #setRepeatingRequest
* @see #setRepeatingBurst
- * @see #configureOutputs
+ * @see CameraDevice#createCaptureSession
*/
public abstract void abortCaptures() throws CameraAccessException;
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 08cfc87..4a87680 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -30,7 +30,7 @@
*
* <p>These properties are fixed for a given CameraDevice, and can be queried
* through the {@link CameraManager CameraManager}
- * interface in addition to through the CameraDevice interface.</p>
+ * interface with {@link CameraManager#getCameraCharacteristics}.</p>
*
* <p>{@link CameraCharacteristics} objects are immutable.</p>
*
@@ -320,7 +320,7 @@
/**
* <p>List of frame rate ranges supported by the
- * AE algorithm/hardware</p>
+ * auto-exposure (AE) algorithm/hardware</p>
*/
public static final Key<android.util.Range<Integer>[]> CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES =
new Key<android.util.Range<Integer>[]>("android.control.aeAvailableTargetFpsRanges", new TypeReference<android.util.Range<Integer>[]>() {{ }});
@@ -343,7 +343,7 @@
new Key<Rational>("android.control.aeCompensationStep", Rational.class);
/**
- * <p>List of AF modes that can be
+ * <p>List of auto-focus (AF) modes that can be
* selected with {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}.</p>
* <p>Not all the auto-focus modes may be supported by a
* given camera device. This entry lists the valid modes for
@@ -496,7 +496,7 @@
new Key<int[]>("android.hotPixel.availableHotPixelModes", int[].class);
/**
- * <p>Supported resolutions for the JPEG thumbnail</p>
+ * <p>Supported resolutions for the JPEG thumbnail.</p>
* <p>Below condiditions will be satisfied for this size list:</p>
* <ul>
* <li>The sizes will be sorted by increasing pixel area (width x height).
@@ -555,7 +555,7 @@
* <p>List containing a subset of the optical image
* stabilization (OIS) modes specified in
* {@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}.</p>
- * <p>If OIS is not implemented for a given camera device, this should
+ * <p>If OIS is not implemented for a given camera device, this will
* contain only OFF.</p>
*
* @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
@@ -612,7 +612,7 @@
/**
* <p>Direction the camera faces relative to
- * device screen</p>
+ * device screen.</p>
* @see #LENS_FACING_FRONT
* @see #LENS_FACING_BACK
*/
@@ -622,7 +622,7 @@
/**
* <p>The set of noise reduction modes supported by this camera device.</p>
* <p>This tag lists the valid modes for {@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}.</p>
- * <p>Full-capability camera devices must laways support OFF and FAST.</p>
+ * <p>Full-capability camera devices must always support OFF and FAST.</p>
*
* @see CaptureRequest#NOISE_REDUCTION_MODE
*/
@@ -778,17 +778,20 @@
new Key<Byte>("android.request.pipelineMaxDepth", byte.class);
/**
- * <p>Optional. Defaults to 1. Defines how many sub-components
+ * <p>Defines how many sub-components
* a result will be composed of.</p>
* <p>In order to combat the pipeline latency, partial results
* may be delivered to the application layer from the camera device as
* soon as they are available.</p>
- * <p>A value of 1 means that partial results are not supported.</p>
- * <p>A typical use case for this might be: after requesting an AF lock the
- * new AF state might be available 50% of the way through the pipeline.
- * The camera device could then immediately dispatch this state via a
- * partial result to the framework/application layer, and the rest of
- * the metadata via later partial results.</p>
+ * <p>Optional; defaults to 1. A value of 1 means that partial
+ * results are not supported, and only the final TotalCaptureResult will
+ * be produced by the camera device.</p>
+ * <p>A typical use case for this might be: after requesting an
+ * auto-focus (AF) lock the new AF state might be available 50%
+ * of the way through the pipeline. The camera device could
+ * then immediately dispatch this state via a partial result to
+ * the application, and the rest of the metadata via later
+ * partial results.</p>
*/
public static final Key<Integer> REQUEST_PARTIAL_RESULT_COUNT =
new Key<Integer>("android.request.partialResultCount", int.class);
@@ -805,8 +808,6 @@
* to do this query each of android.request.availableRequestKeys,
* android.request.availableResultKeys,
* android.request.availableCharacteristicsKeys.</p>
- * <p>XX: Maybe these should go into {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}
- * as a table instead?</p>
* <p>The following capabilities are guaranteed to be available on
* {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} <code>==</code> FULL devices:</p>
* <ul>
@@ -814,14 +815,11 @@
* <li>MANUAL_POST_PROCESSING</li>
* </ul>
* <p>Other capabilities may be available on either FULL or LIMITED
- * devices, but the app. should query this field to be sure.</p>
+ * devices, but the application should query this field to be sure.</p>
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
- * @see #REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
- * @see #REQUEST_AVAILABLE_CAPABILITIES_OPTIONAL
* @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR
* @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING
- * @see #REQUEST_AVAILABLE_CAPABILITIES_ZSL
* @see #REQUEST_AVAILABLE_CAPABILITIES_DNG
*/
public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES =
@@ -837,7 +835,6 @@
* at a more granular level than capabilities. This is especially
* important for optional keys that are not listed under any capability
* in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
- * <p>TODO: This should be used by #getAvailableCaptureRequestKeys.</p>
*
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
* @hide
@@ -862,7 +859,6 @@
* at a more granular level than capabilities. This is especially
* important for optional keys that are not listed under any capability
* in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
- * <p>TODO: This should be used by #getAvailableCaptureResultKeys.</p>
*
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
* @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
@@ -878,7 +874,6 @@
* android.request.availableResultKeys (except that it applies for
* CameraCharacteristics instead of CaptureResult). See above for more
* details.</p>
- * <p>TODO: This should be used by CameraCharacteristics#getKeys.</p>
* @hide
*/
public static final Key<int[]> REQUEST_AVAILABLE_CHARACTERISTICS_KEYS =
@@ -926,10 +921,15 @@
new Key<android.util.Size[]>("android.scaler.availableJpegSizes", android.util.Size[].class);
/**
- * <p>The maximum ratio between active area width
- * and crop region width, or between active area height and
- * crop region height, if the crop region height is larger
- * than width</p>
+ * <p>The maximum ratio between both active area width
+ * and crop region width, and active area height and
+ * crop region height.</p>
+ * <p>This represents the maximum amount of zooming possible by
+ * the camera device, or equivalently, the minimum cropping
+ * window size.</p>
+ * <p>Crop regions that have a width or height that is smaller
+ * than this ratio allows will be rounded up to the minimum
+ * allowed size by the camera device.</p>
*/
public static final Key<Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM =
new Key<Float>("android.scaler.availableMaxDigitalZoom", float.class);
@@ -1326,15 +1326,21 @@
new Key<android.graphics.Rect>("android.sensor.info.activeArraySize", android.graphics.Rect.class);
/**
- * <p>Range of valid sensitivities</p>
+ * <p>Range of valid sensitivities.</p>
+ * <p>The minimum and maximum valid values for the
+ * {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} control.</p>
+ * <p>The values are the standard ISO sensitivity values,
+ * as defined in ISO 12232:2006.</p>
+ *
+ * @see CaptureRequest#SENSOR_SENSITIVITY
*/
public static final Key<android.util.Range<Integer>> SENSOR_INFO_SENSITIVITY_RANGE =
new Key<android.util.Range<Integer>>("android.sensor.info.sensitivityRange", new TypeReference<android.util.Range<Integer>>() {{ }});
/**
- * <p>Arrangement of color filters on sensor;
+ * <p>The arrangement of color filters on sensor;
* represents the colors in the top-left 2x2 section of
- * the sensor, in reading order</p>
+ * the sensor, in reading order.</p>
* @see #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB
* @see #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG
* @see #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG
@@ -1372,8 +1378,11 @@
/**
* <p>The physical dimensions of the full pixel
- * array</p>
- * <p>Needed for FOV calculation for old API</p>
+ * array.</p>
+ * <p>This is the physical size of the sensor pixel
+ * array defined by {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}.</p>
+ *
+ * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
*/
public static final Key<android.util.SizeF> SENSOR_INFO_PHYSICAL_SIZE =
new Key<android.util.SizeF>("android.sensor.info.physicalSize", android.util.SizeF.class);
@@ -1381,9 +1390,17 @@
/**
* <p>Dimensions of full pixel array, possibly
* including black calibration pixels.</p>
- * <p>Maximum output resolution for raw format must
- * match this in
- * android.scaler.availableStreamConfigurations.</p>
+ * <p>The pixel count of the full pixel array,
+ * which covers {@link CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE android.sensor.info.physicalSize} area.</p>
+ * <p>If a camera device supports raw sensor formats, either this
+ * or {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} is the maximum output
+ * raw size listed in {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}.
+ * If a size corresponding to pixelArraySize is listed, the resulting
+ * raw sensor image will include black pixels.</p>
+ *
+ * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CameraCharacteristics#SENSOR_INFO_PHYSICAL_SIZE
*/
public static final Key<android.util.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE =
new Key<android.util.Size>("android.sensor.info.pixelArraySize", android.util.Size.class);
@@ -1406,6 +1423,18 @@
new Key<Integer>("android.sensor.info.whiteLevel", int.class);
/**
+ * <p>The sensor timestamp calibration quality.</p>
+ * <p>The sensor timestamp calibration quality determines the reliability of
+ * {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp} provided by the camera device.</p>
+ *
+ * @see CaptureResult#SENSOR_TIMESTAMP
+ * @see #SENSOR_INFO_TIMESTAMP_CALIBRATION_UNCALIBRATED
+ * @see #SENSOR_INFO_TIMESTAMP_CALIBRATION_CALIBRATED
+ */
+ public static final Key<Integer> SENSOR_INFO_TIMESTAMP_CALIBRATION =
+ new Key<Integer>("android.sensor.info.timestampCalibration", int.class);
+
+ /**
* <p>The standard reference illuminant used as the scene light source when
* calculating the {@link CameraCharacteristics#SENSOR_COLOR_TRANSFORM1 android.sensor.colorTransform1},
* {@link CameraCharacteristics#SENSOR_CALIBRATION_TRANSFORM1 android.sensor.calibrationTransform1}, and
@@ -1638,8 +1667,8 @@
new Key<Integer>("android.sensor.orientation", int.class);
/**
- * <p>Optional. Defaults to [OFF]. Lists the supported test
- * pattern modes for {@link CaptureRequest#SENSOR_TEST_PATTERN_MODE android.sensor.testPatternMode}.</p>
+ * <p>Lists the supported sensor test pattern modes for {@link CaptureRequest#SENSOR_TEST_PATTERN_MODE android.sensor.testPatternMode}.</p>
+ * <p>Optional. Defaults to [OFF].</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CaptureRequest#SENSOR_TEST_PATTERN_MODE
@@ -1648,10 +1677,9 @@
new Key<int[]>("android.sensor.availableTestPatternModes", int[].class);
/**
- * <p>Which face detection modes are available,
- * if any</p>
- * <p>OFF means face detection is disabled, it must
- * be included in the list.</p>
+ * <p>The face detection modes that are available
+ * for this camera device.</p>
+ * <p>OFF is always supported.</p>
* <p>SIMPLE means the device supports the
* android.statistics.faceRectangles and
* android.statistics.faceScores outputs.</p>
@@ -1663,8 +1691,8 @@
new Key<int[]>("android.statistics.info.availableFaceDetectModes", int[].class);
/**
- * <p>Maximum number of simultaneously detectable
- * faces</p>
+ * <p>The maximum number of simultaneously detectable
+ * faces.</p>
*/
public static final Key<Integer> STATISTICS_INFO_MAX_FACE_COUNT =
new Key<Integer>("android.statistics.info.maxFaceCount", int.class);
@@ -1673,7 +1701,7 @@
* <p>The set of hot pixel map output modes supported by this camera device.</p>
* <p>This tag lists valid output modes for {@link CaptureRequest#STATISTICS_HOT_PIXEL_MAP_MODE android.statistics.hotPixelMapMode}.</p>
* <p>If no hotpixel map is available for this camera device, this will contain
- * only OFF. If the hotpixel map is available, this should include both
+ * only OFF. If the hotpixel map is available, this will include both
* the ON and OFF options.</p>
*
* @see CaptureRequest#STATISTICS_HOT_PIXEL_MAP_MODE
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index e9213c5..1f89d33 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -52,7 +52,7 @@
* Create a request suitable for a camera preview window. Specifically, this
* means that high frame rate is given priority over the highest-quality
* post-processing. These requests would normally be used with the
- * {@link #setRepeatingRequest} method.
+ * {@link CameraCaptureSession#setRepeatingRequest} method.
*
* @see #createCaptureRequest
*/
@@ -61,7 +61,7 @@
/**
* Create a request suitable for still image capture. Specifically, this
* means prioritizing image quality over frame rate. These requests would
- * commonly be used with the {@link #capture} method.
+ * commonly be used with the {@link CameraCaptureSession#capture} method.
*
* @see #createCaptureRequest
*/
@@ -71,7 +71,7 @@
* Create a request suitable for video recording. Specifically, this means
* that a stable frame rate is used, and post-processing is set for
* recording quality. These requests would commonly be used with the
- * {@link #setRepeatingRequest} method.
+ * {@link CameraCaptureSession#setRepeatingRequest} method.
*
* @see #createCaptureRequest
*/
@@ -81,8 +81,8 @@
* Create a request suitable for still image capture while recording
* video. Specifically, this means maximizing image quality without
* disrupting the ongoing recording. These requests would commonly be used
- * with the {@link #capture} method while a request based on
- * {@link #TEMPLATE_RECORD} is is in use with {@link #setRepeatingRequest}.
+ * with the {@link CameraCaptureSession#capture} method while a request based on
+ * {@link #TEMPLATE_RECORD} is is in use with {@link CameraCaptureSession#setRepeatingRequest}.
*
* @see #createCaptureRequest
*/
@@ -132,116 +132,6 @@
/**
* <p>Set up a new output set of Surfaces for the camera device.</p>
*
- * <p>The configuration determines the set of potential output Surfaces for
- * the camera device for each capture request. A given request may use all
- * or a only some of the outputs. This method must be called before requests
- * can be submitted to the camera with {@link #capture capture},
- * {@link #captureBurst captureBurst},
- * {@link #setRepeatingRequest setRepeatingRequest}, or
- * {@link #setRepeatingBurst setRepeatingBurst}.</p>
- *
- * <p>Surfaces suitable for inclusion as a camera output can be created for
- * various use cases and targets:</p>
- *
- * <ul>
- *
- * <li>For drawing to a {@link android.view.SurfaceView SurfaceView}: Set
- * the size of the Surface with
- * {@link android.view.SurfaceHolder#setFixedSize} to be one of the
- * supported
- * {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes}
- * before calling {@link android.view.SurfaceHolder#getSurface}.</li>
- *
- * <li>For accessing through an OpenGL texture via a
- * {@link android.graphics.SurfaceTexture SurfaceTexture}: Set the size of
- * the SurfaceTexture with
- * {@link android.graphics.SurfaceTexture#setDefaultBufferSize} to be one
- * of the supported
- * {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes}
- * before creating a Surface from the SurfaceTexture with
- * {@link Surface#Surface}.</li>
- *
- * <li>For recording with {@link android.media.MediaCodec}: Call
- * {@link android.media.MediaCodec#createInputSurface} after configuring
- * the media codec to use one of the
- * {@link StreamConfigurationMap#getOutputSizes(Class) processed sizes}
- * </li>
- *
- * <li>For recording with {@link android.media.MediaRecorder}: TODO</li>
- *
- * <li>For efficient YUV processing with {@link android.renderscript}:
- * Create a RenderScript
- * {@link android.renderscript.Allocation Allocation} with a supported YUV
- * type, the IO_INPUT flag, and one of the supported
- * {@link StreamConfigurationMap#getOutputSizes(int) processed sizes}. Then
- * obtain the Surface with
- * {@link android.renderscript.Allocation#getSurface}.</li>
- *
- * <li>For access to uncompressed or {@link ImageFormat#JPEG JPEG} data in the application:
- * Create a {@link android.media.ImageReader} object with the desired
- * {@link StreamConfigurationMap#getOutputFormats() image format}, and a size from the matching
- * {@link StreamConfigurationMap#getOutputSizes(int) processed size} and {@code format}.
- * Then obtain a {@link Surface} from it.</li>
- * </ul>
- *
- * </p>
- *
- * <p>This function can take several hundred milliseconds to execute, since
- * camera hardware may need to be powered on or reconfigured.</p>
- *
- * <p>The camera device will query each Surface's size and formats upon this
- * call, so they must be set to a valid setting at this time (in particular:
- * if the format is user-visible, it must be one of
- * {@link StreamConfigurationMap#getOutputFormats}; and the size must be one of
- * {@link StreamConfigurationMap#getOutputSizes(int)}).</p>
- *
- * <p>When this method is called with valid Surfaces, the device will transition to the {@link
- * StateListener#onBusy busy state}. Once configuration is complete, the device will transition
- * into the {@link StateListener#onIdle idle state}. Capture requests using the newly-configured
- * Surfaces may then be submitted with {@link #capture}, {@link #captureBurst}, {@link
- * #setRepeatingRequest}, or {@link #setRepeatingBurst}.</p>
- *
- * <p>If this method is called while the camera device is still actively processing previously
- * submitted captures, then the following sequence of events occurs: The device transitions to
- * the busy state and calls the {@link StateListener#onBusy} callback. Second, if a repeating
- * request is set it is cleared. Third, the device finishes up all in-flight and pending
- * requests. Finally, once the device is idle, it then reconfigures its outputs, and calls the
- * {@link StateListener#onIdle} method once it is again ready to accept capture
- * requests. Therefore, no submitted work is discarded. To idle as fast as possible, use {@link
- * #flush} and wait for the idle callback before calling configureOutputs. This will discard
- * work, but reaches the new configuration sooner.</p>
- *
- * <p>Using larger resolution outputs, or more outputs, can result in slower
- * output rate from the device.</p>
- *
- * <p>Configuring the outputs with an empty or null list will transition the camera into an
- * {@link StateListener#onUnconfigured unconfigured state} instead of the {@link
- * StateListener#onIdle idle state}. </p>
- *
- * <p>Calling configureOutputs with the same arguments as the last call to
- * configureOutputs has no effect, and the {@link StateListener#onBusy busy}
- * and {@link StateListener#onIdle idle} state transitions will happen
- * immediately.</p>
- *
- * @param outputs The new set of Surfaces that should be made available as
- * targets for captured image data.
- *
- * @throws IllegalArgumentException if the set of output Surfaces do not
- * meet the requirements
- * @throws CameraAccessException if the camera device is no longer connected or has
- * encountered a fatal error
- * @throws IllegalStateException if the camera device is not idle, or
- * if the camera device has been closed
- *
- * @see StateListener#onBusy
- * @see StateListener#onIdle
- * @see StateListener#onActive
- * @see StateListener#onUnconfigured
- * @see #stopRepeating
- * @see #flush
- * @see StreamConfigurationMap#getOutputFormats()
- * @see StreamConfigurationMap#getOutputSizes(int)
- * @see StreamConfigurationMap#getOutputSizes(Class)
* @deprecated Use {@link #createCaptureSession} instead
*/
@Deprecated
@@ -264,10 +154,11 @@
*
* <ul>
*
- * <li>For drawing to a {@link android.view.SurfaceView SurfaceView}: Set the size of the
- * Surface with {@link android.view.SurfaceHolder#setFixedSize} to be one of the sizes
- * returned by
- * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(SurfaceView.class)}
+ * <li>For drawing to a {@link android.view.SurfaceView SurfaceView}: Once the SurfaceView's
+ * Surface is {@link android.view.SurfaceHolder.Callback#surfaceCreated created}, set the
+ * size of the Surface with {@link android.view.SurfaceHolder#setFixedSize} to be one of the
+ * sizes returned by
+ * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(SurfaceHolder.class)}
* and then obtain the Surface by calling {@link android.view.SurfaceHolder#getSurface}.</li>
*
* <li>For accessing through an OpenGL texture via a
@@ -300,22 +191,18 @@
* Then obtain the Surface with
* {@link android.renderscript.Allocation#getSurface}.</li>
*
- * <li>For access to raw, uncompressed or JPEG data in the application: Create a
- * {@link android.media.ImageReader} object with the one of the supported
- * {@link StreamConfigurationMap#getOutputFormats() output image formats}, and a
- * size from the supported
- * {@link StreamConfigurationMap#getOutputSizes(int) sizes for that format}. Then obtain
- * a Surface from it with {@link android.media.ImageReader#getSurface}.</li>
+ * <li>For access to raw, uncompressed JPEG data in the application: Create an
+ * {@link android.media.ImageReader} object with one of the supported output formats given by
+ * {@link StreamConfigurationMap#getOutputFormats()}, setting its size to one of the
+ * corresponding supported sizes by passing the chosen output format into
+ * {@link StreamConfigurationMap#getOutputSizes(int)}. Then obtain a
+ * {@link android.view.Surface} from it with {@link android.media.ImageReader#getSurface()}.
+ * </li>
*
* </ul>
*
- * </p>
- *
* <p>The camera device will query each Surface's size and formats upon this
- * call, so they must be set to a valid setting at this time (in particular:
- * if the format is user-visible, it must be one of
- * {@link StreamConfigurationMap#getOutputFormats}; and the size must be one of
- * {@link StreamConfigurationMap#getOutputSizes(int)}).</p>
+ * call, so they must be set to a valid setting at this time.</p>
*
* <p>It can take several hundred milliseconds for the session's configuration to complete,
* since camera hardware may need to be powered on or reconfigured. Once the configuration is
@@ -342,10 +229,7 @@
* @param listener The listener to notify about the status of the new capture session.
* @param handler The handler on which the listener should be invoked, or {@code null} to use
* the current thread's {@link android.os.Looper looper}.
- * <!--
- * @return A new camera capture session to use, or null if an empty/null set of Surfaces is
- * provided.
- * -->
+ *
* @throws IllegalArgumentException if the set of output Surfaces do not meet the requirements,
* the listener is null, or the handler is null but the current
* thread has no looper.
@@ -393,92 +277,16 @@
/**
* <p>Submit a request for an image to be captured by this CameraDevice.</p>
*
- * <p>The request defines all the parameters for capturing the single image,
- * including sensor, lens, flash, and post-processing settings.</p>
- *
- * <p>Each request will produce one {@link CaptureResult} and produce new
- * frames for one or more target Surfaces, set with the CaptureRequest
- * builder's {@link CaptureRequest.Builder#addTarget} method. The target
- * surfaces must be configured as active outputs with
- * {@link #configureOutputs} before calling this method.</p>
- *
- * <p>Multiple requests can be in progress at once. They are processed in
- * first-in, first-out order, with minimal delays between each
- * capture. Requests submitted through this method have higher priority than
- * those submitted through {@link #setRepeatingRequest} or
- * {@link #setRepeatingBurst}, and will be processed as soon as the current
- * repeat/repeatBurst processing completes.</p>
- *
- * @param request the settings for this capture
- * @param listener The callback object to notify once this request has been
- * processed. If null, no metadata will be produced for this capture,
- * although image data will still be produced.
- * @param handler the handler on which the listener should be invoked, or
- * {@code null} to use the current thread's {@link android.os.Looper
- * looper}.
- *
- * @return int A unique capture sequence ID used by
- * {@link CaptureListener#onCaptureSequenceCompleted}.
- *
- * @throws CameraAccessException if the camera device is no longer connected or has
- * encountered a fatal error
- * @throws IllegalStateException if the camera is currently busy or unconfigured,
- * or the camera device has been closed.
- * @throws IllegalArgumentException If the request targets Surfaces not
- * currently configured as outputs. Or if the handler is null, the listener
- * is not null, and the calling thread has no looper.
- *
- * @see #captureBurst
- * @see #setRepeatingRequest
- * @see #setRepeatingBurst
- * @deprecated Use {@link CameraCaptureSession} instead
+ * @deprecated Use {@link CameraCaptureSession#capture} instead
*/
@Deprecated
public abstract int capture(CaptureRequest request, CaptureListener listener, Handler handler)
throws CameraAccessException;
/**
- * Submit a list of requests to be captured in sequence as a burst. The
- * burst will be captured in the minimum amount of time possible, and will
- * not be interleaved with requests submitted by other capture or repeat
- * calls.
+ * Submit a list of requests to be captured in sequence as a burst.
*
- * <p>The requests will be captured in order, each capture producing one
- * {@link CaptureResult} and image buffers for one or more target
- * {@link android.view.Surface surfaces}. The target surfaces for each
- * request (set with {@link CaptureRequest.Builder#addTarget}) must be
- * configured as active outputs with {@link #configureOutputs} before
- * calling this method.</p>
- *
- * <p>The main difference between this method and simply calling
- * {@link #capture} repeatedly is that this method guarantees that no
- * other requests will be interspersed with the burst.</p>
- *
- * @param requests the list of settings for this burst capture
- * @param listener The callback object to notify each time one of the
- * requests in the burst has been processed. If null, no metadata will be
- * produced for any requests in this burst, although image data will still
- * be produced.
- * @param handler the handler on which the listener should be invoked, or
- * {@code null} to use the current thread's {@link android.os.Looper
- * looper}.
- *
- * @return int A unique capture sequence ID used by
- * {@link CaptureListener#onCaptureSequenceCompleted}.
- *
- * @throws CameraAccessException if the camera device is no longer connected or has
- * encountered a fatal error
- * @throws IllegalStateException if the camera is currently busy or unconfigured,
- * or the camera device has been closed.
- * @throws IllegalArgumentException If the requests target Surfaces not
- * currently configured as outputs. Or if the handler is null, the listener
- * is not null, and the calling thread has no looper. Or if no requests were
- * passed in.
- *
- * @see #capture
- * @see #setRepeatingRequest
- * @see #setRepeatingBurst
- * @deprecated Use {@link CameraCaptureSession} instead
+ * @deprecated Use {@link CameraCaptureSession#captureBurst} instead
*/
@Deprecated
public abstract int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
@@ -487,58 +295,7 @@
/**
* Request endlessly repeating capture of images by this CameraDevice.
*
- * <p>With this method, the CameraDevice will continually capture images
- * using the settings in the provided {@link CaptureRequest}, at the maximum
- * rate possible.</p>
- *
- * <p>Repeating requests are a simple way for an application to maintain a
- * preview or other continuous stream of frames, without having to
- * continually submit identical requests through {@link #capture}.</p>
- *
- * <p>Repeat requests have lower priority than those submitted
- * through {@link #capture} or {@link #captureBurst}, so if
- * {@link #capture} is called when a repeating request is active, the
- * capture request will be processed before any further repeating
- * requests are processed.<p>
- *
- * <p>Repeating requests are a simple way for an application to maintain a
- * preview or other continuous stream of frames, without having to submit
- * requests through {@link #capture} at video rates.</p>
- *
- * <p>To stop the repeating capture, call {@link #stopRepeating}. Calling
- * {@link #flush} will also clear the request.</p>
- *
- * <p>Calling this method will replace any earlier repeating request or
- * burst set up by this method or {@link #setRepeatingBurst}, although any
- * in-progress burst will be completed before the new repeat request will be
- * used.</p>
- *
- * @param request the request to repeat indefinitely
- * @param listener The callback object to notify every time the
- * request finishes processing. If null, no metadata will be
- * produced for this stream of requests, although image data will
- * still be produced.
- * @param handler the handler on which the listener should be invoked, or
- * {@code null} to use the current thread's {@link android.os.Looper
- * looper}.
- *
- * @return int A unique capture sequence ID used by
- * {@link CaptureListener#onCaptureSequenceCompleted}.
- *
- * @throws CameraAccessException if the camera device is no longer connected or has
- * encountered a fatal error
- * @throws IllegalStateException if the camera is currently busy or unconfigured,
- * or the camera device has been closed.
- * @throws IllegalArgumentException If the requests reference Surfaces not
- * currently configured as outputs. Or if the handler is null, the listener
- * is not null, and the calling thread has no looper.
- *
- * @see #capture
- * @see #captureBurst
- * @see #setRepeatingBurst
- * @see #stopRepeating
- * @see #flush
- * @deprecated Use {@link CameraCaptureSession} instead
+ * @deprecated Use {@link CameraCaptureSession#setRepeatingRequest} instead
*/
@Deprecated
public abstract int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
@@ -548,58 +305,7 @@
* <p>Request endlessly repeating capture of a sequence of images by this
* CameraDevice.</p>
*
- * <p>With this method, the CameraDevice will continually capture images,
- * cycling through the settings in the provided list of
- * {@link CaptureRequest CaptureRequests}, at the maximum rate possible.</p>
- *
- * <p>If a request is submitted through {@link #capture} or
- * {@link #captureBurst}, the current repetition of the request list will be
- * completed before the higher-priority request is handled. This guarantees
- * that the application always receives a complete repeat burst captured in
- * minimal time, instead of bursts interleaved with higher-priority
- * captures, or incomplete captures.</p>
- *
- * <p>Repeating burst requests are a simple way for an application to
- * maintain a preview or other continuous stream of frames where each
- * request is different in a predicatable way, without having to continually
- * submit requests through {@link #captureBurst} .</p>
- *
- * <p>To stop the repeating capture, call {@link #stopRepeating}. Any
- * ongoing burst will still be completed, however. Calling
- * {@link #flush} will also clear the request.</p>
- *
- * <p>Calling this method will replace a previously-set repeating request or
- * burst set up by this method or {@link #setRepeatingRequest}, although any
- * in-progress burst will be completed before the new repeat burst will be
- * used.</p>
- *
- * @param requests the list of requests to cycle through indefinitely
- * @param listener The callback object to notify each time one of the
- * requests in the repeating bursts has finished processing. If null, no
- * metadata will be produced for this stream of requests, although image
- * data will still be produced.
- * @param handler the handler on which the listener should be invoked, or
- * {@code null} to use the current thread's {@link android.os.Looper
- * looper}.
- *
- * @return int A unique capture sequence ID used by
- * {@link CaptureListener#onCaptureSequenceCompleted}.
- *
- * @throws CameraAccessException if the camera device is no longer connected or has
- * encountered a fatal error
- * @throws IllegalStateException if the camera is currently busy or unconfigured,
- * or the camera device has been closed.
- * @throws IllegalArgumentException If the requests reference Surfaces not
- * currently configured as outputs. Or if the handler is null, the listener
- * is not null, and the calling thread has no looper. Or if no requests were
- * passed in.
- *
- * @see #capture
- * @see #captureBurst
- * @see #setRepeatingRequest
- * @see #stopRepeating
- * @see #flush
- * @deprecated Use {@link CameraCaptureSession} instead
+ * @deprecated Use {@link CameraCaptureSession#setRepeatingBurst} instead
*/
@Deprecated
public abstract int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener,
@@ -608,24 +314,9 @@
/**
* <p>Cancel any ongoing repeating capture set by either
* {@link #setRepeatingRequest setRepeatingRequest} or
- * {@link #setRepeatingBurst}. Has no effect on requests submitted through
- * {@link #capture capture} or {@link #captureBurst captureBurst}.</p>
+ * {@link #setRepeatingBurst}.
*
- * <p>Any currently in-flight captures will still complete, as will any
- * burst that is mid-capture. To ensure that the device has finished
- * processing all of its capture requests and is in idle state, wait for the
- * {@link StateListener#onIdle} callback after calling this
- * method..</p>
- *
- * @throws CameraAccessException if the camera device is no longer connected or has
- * encountered a fatal error
- * @throws IllegalStateException if the camera is currently busy or unconfigured,
- * or the camera device has been closed.
- *
- * @see #setRepeatingRequest
- * @see #setRepeatingBurst
- * @see StateListener#onIdle
- * @deprecated Use {@link CameraCaptureSession} instead
+ * @deprecated Use {@link CameraCaptureSession#stopRepeating} instead
*/
@Deprecated
public abstract void stopRepeating() throws CameraAccessException;
@@ -634,36 +325,7 @@
* Flush all captures currently pending and in-progress as fast as
* possible.
*
- * <p>The camera device will discard all of its current work as fast as
- * possible. Some in-flight captures may complete successfully and call
- * {@link CaptureListener#onCaptureCompleted}, while others will trigger
- * their {@link CaptureListener#onCaptureFailed} callbacks. If a repeating
- * request or a repeating burst is set, it will be cleared by the flush.</p>
- *
- * <p>This method is the fastest way to idle the camera device for
- * reconfiguration with {@link #configureOutputs}, at the cost of discarding
- * in-progress work. Once the flush is complete, the idle callback will be
- * called.</p>
- *
- * <p>Flushing will introduce at least a brief pause in the stream of data
- * from the camera device, since once the flush is complete, the first new
- * request has to make it through the entire camera pipeline before new
- * output buffers are produced.</p>
- *
- * <p>This means that using {@code flush()} to simply remove pending
- * requests is not recommended; it's best used for quickly switching output
- * configurations, or for cancelling long in-progress requests (such as a
- * multi-second capture).</p>
- *
- * @throws CameraAccessException if the camera device is no longer connected or has
- * encountered a fatal error
- * @throws IllegalStateException if the camera is not idle/active,
- * or the camera device has been closed.
- *
- * @see #setRepeatingRequest
- * @see #setRepeatingBurst
- * @see #configureOutputs
- * @deprecated Use {@link CameraCaptureSession} instead
+ * @deprecated Use {@link CameraCaptureSession#abortCaptures} instead
*/
@Deprecated
public abstract void flush() throws CameraAccessException;
@@ -690,15 +352,7 @@
* <p>A listener for tracking the progress of a {@link CaptureRequest}
* submitted to the camera device.</p>
*
- * <p>This listener is called when a request triggers a capture to start,
- * and when the capture is complete. In case on an error capturing an image,
- * the error method is triggered instead of the completion method.</p>
- *
- * @see #capture
- * @see #captureBurst
- * @see #setRepeatingRequest
- * @see #setRepeatingBurst
- * @deprecated Use {@link CameraCaptureSession} instead
+ * @deprecated Use {@link CameraCaptureSession.CaptureListener} instead
*/
@Deprecated
public static abstract class CaptureListener {
@@ -715,29 +369,6 @@
* This method is called when the camera device has started capturing
* the output image for the request, at the beginning of image exposure.
*
- * <p>This callback is invoked right as the capture of a frame begins,
- * so it is the most appropriate time for playing a shutter sound,
- * or triggering UI indicators of capture.</p>
- *
- * <p>The request that is being used for this capture is provided, along
- * with the actual timestamp for the start of exposure. This timestamp
- * matches the timestamp that will be included in
- * {@link CaptureResult#SENSOR_TIMESTAMP the result timestamp field},
- * and in the buffers sent to each output Surface. These buffer
- * timestamps are accessible through, for example,
- * {@link android.media.Image#getTimestamp() Image.getTimestamp()} or
- * {@link android.graphics.SurfaceTexture#getTimestamp()}.</p>
- *
- * <p>For the simplest way to play a shutter sound camera shutter or a
- * video recording start/stop sound, see the
- * {@link android.media.MediaActionSound} class.</p>
- *
- * <p>The default implementation of this method does nothing.</p>
- *
- * @param camera the CameraDevice sending the callback
- * @param request the request for the capture that just begun
- * @param timestamp the timestamp at start of capture, in nanoseconds.
- *
* @see android.media.MediaActionSound
*/
public void onCaptureStarted(CameraDevice camera,
@@ -749,25 +380,6 @@
* This method is called when some results from an image capture are
* available.
*
- * <p>The result provided here will contain some subset of the fields of
- * a full result. Multiple onCapturePartial calls may happen per
- * capture; a given result field will only be present in one partial
- * capture at most. The final onCaptureCompleted call will always
- * contain all the fields, whether onCapturePartial was called or
- * not.</p>
- *
- * <p>The default implementation of this method does nothing.</p>
- *
- * @param camera The CameraDevice sending the callback.
- * @param request The request that was given to the CameraDevice
- * @param result The partial output metadata from the capture, which
- * includes a subset of the CaptureResult fields.
- *
- * @see #capture
- * @see #captureBurst
- * @see #setRepeatingRequest
- * @see #setRepeatingBurst
- *
* @hide
*/
public void onCapturePartial(CameraDevice camera,
@@ -779,37 +391,6 @@
* This method is called when an image capture makes partial forward progress; some
* (but not all) results from an image capture are available.
*
- * <p>The result provided here will contain some subset of the fields of
- * a full result. Multiple {@link #onCaptureProgressed} calls may happen per
- * capture; a given result field will only be present in one partial
- * capture at most. The final {@link #onCaptureCompleted} call will always
- * contain all the fields (in particular, the union of all the fields of all
- * the partial results composing the total result).</p>
- *
- * <p>For each request, some result data might be available earlier than others. The typical
- * delay between each partial result (per request) is a single frame interval.
- * For performance-oriented use-cases, applications should query the metadata they need
- * to make forward progress from the partial results and avoid waiting for the completed
- * result.</p>
- *
- * <p>Each request will generate at least {@code 1} partial results, and at most
- * {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT} partial results.</p>
- *
- * <p>Depending on the request settings, the number of partial results per request
- * will vary, although typically the partial count could be the same as long as the
- * camera device subsystems enabled stay the same.</p>
- *
- * <p>The default implementation of this method does nothing.</p>
- *
- * @param camera The CameraDevice sending the callback.
- * @param request The request that was given to the CameraDevice
- * @param partialResult The partial output metadata from the capture, which
- * includes a subset of the {@link TotalCaptureResult} fields.
- *
- * @see #capture
- * @see #captureBurst
- * @see #setRepeatingRequest
- * @see #setRepeatingBurst
*/
public void onCaptureProgressed(CameraDevice camera,
CaptureRequest request, CaptureResult partialResult) {
@@ -819,26 +400,6 @@
/**
* This method is called when an image capture has fully completed and all the
* result metadata is available.
- *
- * <p>This callback will always fire after the last {@link #onCaptureProgressed};
- * in other words, no more partial results will be delivered once the completed result
- * is available.</p>
- *
- * <p>For performance-intensive use-cases where latency is a factor, consider
- * using {@link #onCaptureProgressed} instead.</p>
- *
- * <p>The default implementation of this method does nothing.</p>
- *
- * @param camera The CameraDevice sending the callback.
- * @param request The request that was given to the CameraDevice
- * @param result The total output metadata from the capture, including the
- * final capture parameters and the state of the camera system during
- * capture.
- *
- * @see #capture
- * @see #captureBurst
- * @see #setRepeatingRequest
- * @see #setRepeatingBurst
*/
public void onCaptureCompleted(CameraDevice camera,
CaptureRequest request, TotalCaptureResult result) {
@@ -849,29 +410,6 @@
* This method is called instead of {@link #onCaptureCompleted} when the
* camera device failed to produce a {@link CaptureResult} for the
* request.
- *
- * <p>Other requests are unaffected, and some or all image buffers from
- * the capture may have been pushed to their respective output
- * streams.</p>
- *
- * <p>Some partial results may have been delivered before the capture fails;
- * however after this callback fires, no more partial results will be delivered by
- * {@link #onCaptureProgressed}.</p>
- *
- * <p>The default implementation of this method does nothing.</p>
- *
- * @param camera
- * The CameraDevice sending the callback.
- * @param request
- * The request that was given to the CameraDevice
- * @param failure
- * The output failure from the capture, including the failure reason
- * and the frame number.
- *
- * @see #capture
- * @see #captureBurst
- * @see #setRepeatingRequest
- * @see #setRepeatingBurst
*/
public void onCaptureFailed(CameraDevice camera,
CaptureRequest request, CaptureFailure failure) {
@@ -882,26 +420,6 @@
* This method is called independently of the others in CaptureListener,
* when a capture sequence finishes and all {@link CaptureResult}
* or {@link CaptureFailure} for it have been returned via this listener.
- *
- * <p>In total, there will be at least one result/failure returned by this listener
- * before this callback is invoked. If the capture sequence is aborted before any
- * requests have been processed, {@link #onCaptureSequenceAborted} is invoked instead.</p>
- *
- * <p>The default implementation does nothing.</p>
- *
- * @param camera
- * The CameraDevice sending the callback.
- * @param sequenceId
- * A sequence ID returned by the {@link #capture} family of functions.
- * @param frameNumber
- * The last frame number (returned by {@link CaptureResult#getFrameNumber}
- * or {@link CaptureFailure#getFrameNumber}) in the capture sequence.
- *
- * @see CaptureResult#getFrameNumber()
- * @see CaptureFailure#getFrameNumber()
- * @see CaptureResult#getSequenceId()
- * @see CaptureFailure#getSequenceId()
- * @see #onCaptureSequenceAborted
*/
public void onCaptureSequenceCompleted(CameraDevice camera,
int sequenceId, long frameNumber) {
@@ -912,25 +430,6 @@
* This method is called independently of the others in CaptureListener,
* when a capture sequence aborts before any {@link CaptureResult}
* or {@link CaptureFailure} for it have been returned via this listener.
- *
- * <p>Due to the asynchronous nature of the camera device, not all submitted captures
- * are immediately processed. It is possible to clear out the pending requests
- * by a variety of operations such as {@link CameraDevice#stopRepeating} or
- * {@link CameraDevice#flush}. When such an event happens,
- * {@link #onCaptureSequenceCompleted} will not be called.</p>
- *
- * <p>The default implementation does nothing.</p>
- *
- * @param camera
- * The CameraDevice sending the callback.
- * @param sequenceId
- * A sequence ID returned by the {@link #capture} family of functions.
- *
- * @see CaptureResult#getFrameNumber()
- * @see CaptureFailure#getFrameNumber()
- * @see CaptureResult#getSequenceId()
- * @see CaptureFailure#getSequenceId()
- * @see #onCaptureSequenceCompleted
*/
public void onCaptureSequenceAborted(CameraDevice camera,
int sequenceId) {
@@ -945,14 +444,14 @@
* <p>A listener must be provided to the {@link CameraManager#openCamera}
* method to open a camera device.</p>
*
- * <p>These events include notifications about the device becoming idle (
- * allowing for {@link #configureOutputs} to be called), about device
- * disconnection, and about unexpected device errors.</p>
+ * <p>These events include notifications about the device completing startup (
+ * allowing for {@link #createCaptureSession} to be called), about device
+ * disconnection or closure, and about unexpected device errors.</p>
*
- * <p>Events about the progress of specific {@link CaptureRequest
- * CaptureRequests} are provided through a {@link CaptureListener} given to
- * the {@link #capture}, {@link #captureBurst}, {@link
- * #setRepeatingRequest}, or {@link #setRepeatingBurst} methods.
+ * <p>Events about the progress of specific {@link CaptureRequest CaptureRequests} are provided
+ * through a {@link CameraCaptureSession.CaptureListener} given to the
+ * {@link CameraCaptureSession#capture}, {@link CameraCaptureSession#captureBurst},
+ * {@link CameraCaptureSession#setRepeatingRequest}, or {@link CameraCaptureSession#setRepeatingBurst} methods.
*
* @see CameraManager#openCamera
*/
@@ -1026,8 +525,9 @@
/**
* The method called when a camera device has finished opening.
*
- * <p>An opened camera will immediately afterwards transition into
- * {@link #onUnconfigured}.</p>
+ * <p>At this point, the camera device is ready to use, and
+ * {@link CameraDevice#createCaptureSession} can be called to set up the first capture
+ * session.</p>
*
* @param camera the camera device that has become opened
*/
@@ -1036,21 +536,7 @@
/**
* The method called when a camera device has no outputs configured.
*
- * <p>An unconfigured camera device needs to be configured with
- * {@link CameraDevice#configureOutputs} before being able to
- * submit any capture request.</p>
- *
- * <p>This state may be entered by a newly opened camera or by
- * calling {@link CameraDevice#configureOutputs} with a null/empty
- * list of Surfaces when idle.</p>
- *
- * <p>Any attempts to submit a capture request while in this state
- * will result in an {@link IllegalStateException} being thrown.</p>
- *
- * <p>The default implementation of this method does nothing.</p>
- *
- * @param camera the camera device has that become unconfigured
- * @deprecated Use {@link CameraCaptureSession.StateListener} instead.
+ * @deprecated Use {@link #onOpened} instead.
*/
@Deprecated
public void onUnconfigured(CameraDevice camera) {
@@ -1061,27 +547,7 @@
* The method called when a camera device begins processing
* {@link CaptureRequest capture requests}.
*
- * <p>A camera may not be re-configured while in this state. The camera
- * will transition to the idle state once all pending captures have
- * completed. If a repeating request is set, the camera will remain active
- * until it is cleared and the remaining requests finish processing. To
- * transition to the idle state as quickly as possible, call {@link #flush()},
- * which will idle the camera device as quickly as possible, likely canceling
- * most in-progress captures.</p>
- *
- * <p>All calls except for {@link CameraDevice#configureOutputs} are
- * legal while in this state.
- * </p>
- *
- * <p>The default implementation of this method does nothing.</p>
- *
- * @param camera the camera device that has become active
- *
- * @see CameraDevice#capture
- * @see CameraDevice#captureBurst
- * @see CameraDevice#setRepeatingBurst
- * @see CameraDevice#setRepeatingRequest
- * @deprecated Use {@link CameraCaptureSession.StateListener} instead.
+ * @deprecated Use {@link CameraCaptureSession.StateListener#onActive} instead.
*/
@Deprecated
public void onActive(CameraDevice camera) {
@@ -1091,32 +557,7 @@
/**
* The method called when a camera device is busy.
*
- * <p>A camera becomes busy while it's outputs are being configured
- * (after a call to {@link CameraDevice#configureOutputs} or while it's
- * being flushed (after a call to {@link CameraDevice#flush}.</p>
- *
- * <p>Once the on-going operations are complete, the camera will automatically
- * transition into {@link #onIdle} if there is at least one configured output,
- * or {@link #onUnconfigured} otherwise.</p>
- *
- * <p>Any attempts to manipulate the camera while its is busy
- * will result in an {@link IllegalStateException} being thrown.</p>
- *
- * <p>Only the following methods are valid to call while in this state:
- * <ul>
- * <li>{@link CameraDevice#getId}</li>
- * <li>{@link CameraDevice#createCaptureRequest}</li>
- * <li>{@link CameraDevice#close}</li>
- * </ul>
- * </p>
- *
- * <p>The default implementation of this method does nothing.</p>
- *
- * @param camera the camera device that has become busy
- *
- * @see CameraDevice#configureOutputs
- * @see CameraDevice#flush
- * @deprecated Use {@link CameraCaptureSession.StateListener} instead.
+ * @deprecated Use {@link CameraCaptureSession.StateListener#onConfigured} instead.
*/
@Deprecated
public void onBusy(CameraDevice camera) {
@@ -1142,30 +583,7 @@
* The method called when a camera device has finished processing all
* submitted capture requests and has reached an idle state.
*
- * <p>An idle camera device can have its outputs changed by calling {@link
- * CameraDevice#configureOutputs}, which will transition it into the busy state.</p>
- *
- * <p>To idle and reconfigure outputs without canceling any submitted
- * capture requests, the application needs to clear its repeating
- * request/burst, if set, with {@link CameraDevice#stopRepeating}, and
- * then wait for this callback to be called before calling {@link
- * CameraDevice#configureOutputs}.</p>
- *
- * <p>To idle and reconfigure a camera device as fast as possible, the
- * {@link CameraDevice#flush} method can be used, which will discard all
- * pending and in-progress capture requests. Once the {@link
- * CameraDevice#flush} method is called, the application must wait for
- * this callback to fire before calling {@link
- * CameraDevice#configureOutputs}.</p>
- *
- * <p>The default implementation of this method does nothing.</p>
- *
- * @param camera the camera device that has become idle
- *
- * @see CameraDevice#configureOutputs
- * @see CameraDevice#stopRepeating
- * @see CameraDevice#flush
- * @deprecated Use {@link CameraCaptureSession.StateListener} instead.
+ * @deprecated Use {@link CameraCaptureSession.StateListener#onReady} instead.
*/
@Deprecated
public void onIdle(CameraDevice camera) {
@@ -1221,7 +639,7 @@
*
* @param camera The device reporting the error
* @param error The error code, one of the
- * {@code CameraDeviceListener.ERROR_*} values.
+ * {@code StateListener.ERROR_*} values.
*
* @see #ERROR_CAMERA_DEVICE
* @see #ERROR_CAMERA_SERVICE
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 7c0f37e6..0901562 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -35,7 +35,7 @@
import java.util.ArrayList;
/**
- * <p>An interface for iterating, listing, and connecting to
+ * <p>A system service manager for detecting, characterizing, and connecting to
* {@link CameraDevice CameraDevices}.</p>
*
* <p>You can get an instance of this class by calling
@@ -357,14 +357,18 @@
}
/**
- * Interface for listening to camera devices becoming available or
- * unavailable.
+ * A listener for camera devices becoming available or
+ * unavailable to open.
*
* <p>Cameras become available when they are no longer in use, or when a new
* removable camera is connected. They become unavailable when some
* application or service starts using a camera, or when a removable camera
* is disconnected.</p>
*
+ * <p>Extend this listener and pass an instance of the subclass to
+ * {@link CameraManager#addAvailabilityListener} to be notified of such availability
+ * changes.</p>
+ *
* @see addAvailabilityListener
*/
public static abstract class AvailabilityListener {
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 94a5a79..5a02435 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -157,8 +157,8 @@
/**
* <p>The lens focus distance is not accurate, and the units used for
- * {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} do not correspond to any physical units.
- * Setting the lens to the same focus distance on separate occasions may
+ * {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} do not correspond to any physical units.</p>
+ * <p>Setting the lens to the same focus distance on separate occasions may
* result in a different real focus distance, depending on factors such
* as the orientation of the device, the age of the focusing mechanism,
* and the device temperature. The focus distance value will still be
@@ -172,20 +172,24 @@
public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED = 0;
/**
- * <p>The lens focus distance is measured in diopters. However, setting the lens
- * to the same focus distance on separate occasions may result in a
- * different real focus distance, depending on factors such as the
- * orientation of the device, the age of the focusing mechanism, and
- * the device temperature.</p>
+ * <p>The lens focus distance is measured in diopters.</p>
+ * <p>However, setting the lens to the same focus distance
+ * on separate occasions may result in a different real
+ * focus distance, depending on factors such as the
+ * orientation of the device, the age of the focusing
+ * mechanism, and the device temperature.</p>
* @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
*/
public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE = 1;
/**
- * <p>The lens focus distance is measured in diopters. The lens mechanism is
- * calibrated so that setting the same focus distance is repeatable on
- * multiple occasions with good accuracy, and the focus distance corresponds
- * to the real physical distance to the plane of best focus.</p>
+ * <p>The lens focus distance is measured in diopters, and
+ * is calibrated.</p>
+ * <p>The lens mechanism is calibrated so that setting the
+ * same focus distance is repeatable on multiple
+ * occasions with good accuracy, and the focus distance
+ * corresponds to the real physical distance to the plane
+ * of best focus.</p>
* @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
*/
public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED = 2;
@@ -195,11 +199,13 @@
//
/**
+ * <p>The camera device faces the same direction as the device's screen.</p>
* @see CameraCharacteristics#LENS_FACING
*/
public static final int LENS_FACING_FRONT = 0;
/**
+ * <p>The camera device faces the opposite direction as the device's screen.</p>
* @see CameraCharacteristics#LENS_FACING
*/
public static final int LENS_FACING_BACK = 1;
@@ -215,11 +221,10 @@
* <p>The full set of features supported by this capability makes
* the camera2 api backwards compatible with the camera1
* (android.hardware.Camera) API.</p>
- * <p>TODO: @hide this. Doesn't really mean anything except
- * act as a catch-all for all the 'base' functionality.</p>
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @hide
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0;
@@ -228,15 +233,14 @@
* tags or functionality not encapsulated by one of the other
* capabilities.</p>
* <p>A typical example is all tags marked 'optional'.</p>
- * <p>TODO: @hide. We may not need this if we @hide all the optional
- * tags not belonging to a capability.</p>
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @hide
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_OPTIONAL = 1;
/**
* <p>The camera device can be manually controlled (3A algorithms such
- * as auto exposure, and auto focus can be bypassed).
+ * as auto-exposure, and auto-focus can be bypassed).
* The camera device supports basic manual control of the sensor image
* acquisition related stages. This means the following controls are
* guaranteed to be supported:</p>
@@ -257,11 +261,11 @@
* <li>{@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}</li>
* </ul>
* </li>
- * <li>Manual lens control<ul>
+ * <li>Manual lens control (if the lens is adjustable)<ul>
* <li>android.lens.*</li>
* </ul>
* </li>
- * <li>Manual flash control<ul>
+ * <li>Manual flash control (if a flash unit is present)<ul>
* <li>android.flash.*</li>
* </ul>
* </li>
@@ -312,8 +316,6 @@
* </ul>
* <p>If auto white balance is enabled, then the camera device
* will accurately report the values applied by AWB in the result.</p>
- * <p>The camera device will also support everything in MANUAL_SENSOR
- * except manual lens control and manual flash control.</p>
* <p>A given camera device may also support additional post-processing
* controls, but this capability only covers the above list of controls.</p>
*
@@ -340,8 +342,8 @@
* (both input/output) will match the maximum available
* resolution of JPEG streams.</li>
* </ul>
- * <p>@hide this, TODO: remove it when input related APIs are ready.</p>
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @hide
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4;
@@ -355,12 +357,14 @@
* <li>RAW16 is reprocessable into both YUV_420_888 and JPEG
* formats.</li>
* <li>The maximum available resolution for RAW16 streams (both
- * input/output) will match the value in
- * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}.</li>
+ * input/output) will match either the value in
+ * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize} or
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</li>
* <li>All DNG-related optional metadata entries are provided
* by the camera device.</li>
* </ul>
*
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
*/
@@ -371,13 +375,13 @@
//
/**
- * <p>The camera device will only support centered crop regions.</p>
+ * <p>The camera device only supports centered crop regions.</p>
* @see CameraCharacteristics#SCALER_CROPPING_TYPE
*/
public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0;
/**
- * <p>The camera device will support arbitrarily chosen crop regions.</p>
+ * <p>The camera device supports arbitrarily chosen crop regions.</p>
* @see CameraCharacteristics#SCALER_CROPPING_TYPE
*/
public static final int SCALER_CROPPING_TYPE_FREEFORM = 1;
@@ -415,6 +419,33 @@
public static final int SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB = 4;
//
+ // Enumeration values for CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION
+ //
+
+ /**
+ * <p>Timestamps from {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp} are in nanoseconds and monotonic,
+ * but can not be compared to timestamps from other subsystems
+ * (e.g. accelerometer, gyro etc.), or other instances of the same or different
+ * camera devices in the same system. Timestamps between streams and results for
+ * a single camera instance are comparable, and the timestamps for all buffers
+ * and the result metadata generated by a single capture are identical.</p>
+ *
+ * @see CaptureResult#SENSOR_TIMESTAMP
+ * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION
+ */
+ public static final int SENSOR_INFO_TIMESTAMP_CALIBRATION_UNCALIBRATED = 0;
+
+ /**
+ * <p>Timestamps from {@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp} are in the same timebase as
+ * android.os.SystemClock#elapsedRealtimeNanos(),
+ * and they can be compared to other timestamps using that base.</p>
+ *
+ * @see CaptureResult#SENSOR_TIMESTAMP
+ * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION
+ */
+ public static final int SENSOR_INFO_TIMESTAMP_CALIBRATION_CALIBRATED = 1;
+
+ //
// Enumeration values for CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT1
//
@@ -523,7 +554,7 @@
//
/**
- * <p>android.led.transmit control is used</p>
+ * <p>android.led.transmit control is used.</p>
* @see CameraCharacteristics#LED_AVAILABLE_LEDS
* @hide
*/
@@ -534,11 +565,14 @@
//
/**
+ * <p>This camera device has only limited capabilities.</p>
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
*/
public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0;
/**
+ * <p>This camera device is capable of supporting advanced imaging
+ * applications.</p>
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
*/
public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1;
@@ -548,9 +582,9 @@
//
/**
- * <p>Every frame has the requests immediately applied.
- * (and furthermore for all results,
- * <code>android.sync.frameNumber == android.request.frameCount</code>)</p>
+ * <p>Every frame has the requests immediately applied.</p>
+ * <p>Furthermore for all results,
+ * <code>android.sync.frameNumber == android.request.frameCount</code></p>
* <p>Changing controls over multiple requests one after another will
* produce results that have those controls applied atomically
* each frame.</p>
@@ -590,8 +624,8 @@
public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0;
/**
- * <p>Must not slow down capture rate relative to sensor raw
- * output.</p>
+ * <p>Color correction processing must not slow down
+ * capture rate relative to sensor raw output.</p>
* <p>Advanced white balance adjustments above and beyond
* the specified white balance pipeline may be applied.</p>
* <p>If AWB is enabled with <code>{@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} != OFF</code>, then
@@ -604,8 +638,9 @@
public static final int COLOR_CORRECTION_MODE_FAST = 1;
/**
- * <p>Capture rate (relative to sensor raw output)
- * may be reduced by high quality.</p>
+ * <p>Color correction processing operates at improved
+ * quality but reduced capture rate (relative to sensor raw
+ * output).</p>
* <p>Advanced white balance adjustments above and beyond
* the specified white balance pipeline may be applied.</p>
* <p>If AWB is enabled with <code>{@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} != OFF</code>, then
@@ -656,8 +691,8 @@
//
/**
- * <p>The camera device's autoexposure routine is disabled;
- * the application-selected {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime},
+ * <p>The camera device's autoexposure routine is disabled.</p>
+ * <p>The application-selected {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime},
* {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} and
* {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} are used by the camera
* device, along with android.flash.* fields, if there's
@@ -672,7 +707,8 @@
/**
* <p>The camera device's autoexposure routine is active,
- * with no flash control. The application's values for
+ * with no flash control.</p>
+ * <p>The application's values for
* {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime},
* {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}, and
* {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} are ignored. The
@@ -689,10 +725,10 @@
/**
* <p>Like ON, except that the camera device also controls
* the camera's flash unit, firing it in low-light
- * conditions. The flash may be fired during a
- * precapture sequence (triggered by
- * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and may be fired
- * for captures for which the
+ * conditions.</p>
+ * <p>The flash may be fired during a precapture sequence
+ * (triggered by {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and
+ * may be fired for captures for which the
* {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} field is set to
* STILL_CAPTURE</p>
*
@@ -705,10 +741,10 @@
/**
* <p>Like ON, except that the camera device also controls
* the camera's flash unit, always firing it for still
- * captures. The flash may be fired during a precapture
- * sequence (triggered by
- * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and will always
- * be fired for captures for which the
+ * captures.</p>
+ * <p>The flash may be fired during a precapture sequence
+ * (triggered by {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and
+ * will always be fired for captures for which the
* {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} field is set to
* STILL_CAPTURE</p>
*
@@ -720,9 +756,10 @@
/**
* <p>Like ON_AUTO_FLASH, but with automatic red eye
- * reduction. If deemed necessary by the camera device,
- * a red eye reduction flash will fire during the
- * precapture sequence.</p>
+ * reduction.</p>
+ * <p>If deemed necessary by the camera device, a red eye
+ * reduction flash will fire during the precapture
+ * sequence.</p>
* @see CaptureRequest#CONTROL_AE_MODE
*/
public static final int CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4;
@@ -739,8 +776,9 @@
/**
* <p>The precapture metering sequence will be started
- * by the camera device. The exact effect of the precapture
- * trigger depends on the current AE mode and state.</p>
+ * by the camera device.</p>
+ * <p>The exact effect of the precapture trigger depends on
+ * the current AE mode and state.</p>
* @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
*/
public static final int CONTROL_AE_PRECAPTURE_TRIGGER_START = 1;
@@ -752,7 +790,7 @@
/**
* <p>The auto-focus routine does not control the lens;
* {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} is controlled by the
- * application</p>
+ * application.</p>
*
* @see CaptureRequest#LENS_FOCUS_DISTANCE
* @see CaptureRequest#CONTROL_AF_MODE
@@ -760,12 +798,14 @@
public static final int CONTROL_AF_MODE_OFF = 0;
/**
- * <p>If lens is not fixed focus.</p>
- * <p>Use {@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} to determine if lens
- * is fixed-focus. In this mode, the lens does not move unless
+ * <p>Basic automatic focus mode.</p>
+ * <p>In this mode, the lens does not move unless
* the autofocus trigger action is called. When that trigger
- * is activated, AF must transition to ACTIVE_SCAN, then to
+ * is activated, AF will transition to ACTIVE_SCAN, then to
* the outcome of the scan (FOCUSED or NOT_FOCUSED).</p>
+ * <p>Always supported if lens is not fixed focus.</p>
+ * <p>Use {@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} to determine if lens
+ * is fixed-focus.</p>
* <p>Triggering AF_CANCEL resets the lens position to default,
* and sets the AF state to INACTIVE.</p>
*
@@ -775,11 +815,16 @@
public static final int CONTROL_AF_MODE_AUTO = 1;
/**
+ * <p>Close-up focusing mode.</p>
* <p>In this mode, the lens does not move unless the
- * autofocus trigger action is called.</p>
- * <p>When that trigger is activated, AF must transition to
+ * autofocus trigger action is called. When that trigger is
+ * activated, AF will transition to ACTIVE_SCAN, then to
+ * the outcome of the scan (FOCUSED or NOT_FOCUSED). This
+ * mode is optimized for focusing on objects very close to
+ * the camera.</p>
+ * <p>When that trigger is activated, AF will transition to
* ACTIVE_SCAN, then to the outcome of the scan (FOCUSED or
- * NOT_FOCUSED). Triggering cancel AF resets the lens
+ * NOT_FOCUSED). Triggering cancel AF resets the lens
* position to default, and sets the AF state to
* INACTIVE.</p>
* @see CaptureRequest#CONTROL_AF_MODE
@@ -830,8 +875,11 @@
public static final int CONTROL_AF_MODE_CONTINUOUS_PICTURE = 4;
/**
- * <p>Extended depth of field (digital focus). AF
- * trigger is ignored, AF state should always be
+ * <p>Extended depth of field (digital focus) mode.</p>
+ * <p>The camera device will produce images with an extended
+ * depth of field automatically; no special focusing
+ * operations need to be done before taking a picture.</p>
+ * <p>AF triggers are ignored, and the AF state will always be
* INACTIVE.</p>
* @see CaptureRequest#CONTROL_AF_MODE
*/
@@ -865,8 +913,8 @@
//
/**
- * <p>The camera device's auto white balance routine is disabled;
- * the application-selected color transform matrix
+ * <p>The camera device's auto-white balance routine is disabled.</p>
+ * <p>The application-selected color transform matrix
* ({@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}) and gains
* ({@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}) are used by the camera
* device for manual white balance control.</p>
@@ -878,9 +926,12 @@
public static final int CONTROL_AWB_MODE_OFF = 0;
/**
- * <p>The camera device's auto white balance routine is active;
- * the application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
- * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.</p>
+ * <p>The camera device's auto-white balance routine is active.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
*
* @see CaptureRequest#COLOR_CORRECTION_GAINS
* @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
@@ -889,65 +940,125 @@
public static final int CONTROL_AWB_MODE_AUTO = 1;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses incandescent light as the assumed scene
- * illumination for white balance. While the exact white balance
- * transforms are up to the camera device, they will approximately
- * match the CIE standard illuminant A.</p>
+ * illumination for white balance.</p>
+ * <p>While the exact white balance transforms are up to the
+ * camera device, they will approximately match the CIE
+ * standard illuminant A.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_INCANDESCENT = 2;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses fluorescent light as the assumed scene
- * illumination for white balance. While the exact white balance
- * transforms are up to the camera device, they will approximately
- * match the CIE standard illuminant F2.</p>
+ * illumination for white balance.</p>
+ * <p>While the exact white balance transforms are up to the
+ * camera device, they will approximately match the CIE
+ * standard illuminant F2.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_FLUORESCENT = 3;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses warm fluorescent light as the assumed scene
- * illumination for white balance. While the exact white balance
- * transforms are up to the camera device, they will approximately
- * match the CIE standard illuminant F4.</p>
+ * illumination for white balance.</p>
+ * <p>While the exact white balance transforms are up to the
+ * camera device, they will approximately match the CIE
+ * standard illuminant F4.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_WARM_FLUORESCENT = 4;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses daylight light as the assumed scene
- * illumination for white balance. While the exact white balance
- * transforms are up to the camera device, they will approximately
- * match the CIE standard illuminant D65.</p>
+ * illumination for white balance.</p>
+ * <p>While the exact white balance transforms are up to the
+ * camera device, they will approximately match the CIE
+ * standard illuminant D65.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_DAYLIGHT = 5;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses cloudy daylight light as the assumed scene
* illumination for white balance.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_CLOUDY_DAYLIGHT = 6;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses twilight light as the assumed scene
* illumination for white balance.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_TWILIGHT = 7;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses shade light as the assumed scene
* illumination for white balance.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_SHADE = 8;
@@ -957,38 +1068,43 @@
//
/**
- * <p>This request doesn't fall into the other
- * categories. Default to preview-like
+ * <p>The goal of this request doesn't fall into the other
+ * categories. The camera device will default to preview-like
* behavior.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_CUSTOM = 0;
/**
- * <p>This request is for a preview-like usecase. The
- * precapture trigger may be used to start off a metering
- * w/flash sequence</p>
+ * <p>This request is for a preview-like use case.</p>
+ * <p>The precapture trigger may be used to start off a metering
+ * w/flash sequence.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_PREVIEW = 1;
/**
* <p>This request is for a still capture-type
- * usecase.</p>
+ * use case.</p>
+ * <p>If the flash unit is under automatic control, it may fire as needed.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_STILL_CAPTURE = 2;
/**
* <p>This request is for a video recording
- * usecase.</p>
+ * use case.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_VIDEO_RECORD = 3;
/**
* <p>This request is for a video snapshot (still
- * image while recording video) usecase</p>
+ * image while recording video) use case.</p>
+ * <p>The camera device should take the highest-quality image
+ * possible (given the other settings) without disrupting the
+ * frame rate of video recording.<br />
+ * </p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT = 4;
@@ -997,15 +1113,16 @@
* <p>This request is for a ZSL usecase; the
* application will stream full-resolution images and
* reprocess one or several later for a final
- * capture</p>
+ * capture.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG = 5;
/**
* <p>This request is for manual capture use case where
- * the applications want to directly control the capture parameters
- * (e.g. {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}, {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} etc.).</p>
+ * the applications want to directly control the capture parameters.</p>
+ * <p>For example, the application may wish to manually control
+ * {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}, {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}, etc.</p>
*
* @see CaptureRequest#SENSOR_EXPOSURE_TIME
* @see CaptureRequest#SENSOR_SENSITIVITY
@@ -1025,7 +1142,8 @@
/**
* <p>A "monocolor" effect where the image is mapped into
- * a single color. This will typically be grayscale.</p>
+ * a single color.</p>
+ * <p>This will typically be grayscale.</p>
* @see CaptureRequest#CONTROL_EFFECT_MODE
*/
public static final int CONTROL_EFFECT_MODE_MONO = 1;
@@ -1085,31 +1203,42 @@
//
/**
- * <p>Full application control of pipeline. All 3A
- * routines are disabled, no other settings in
- * android.control.* have any effect</p>
+ * <p>Full application control of pipeline.</p>
+ * <p>All control by the device's metering and focusing (3A)
+ * routines is disabled, and no other settings in
+ * android.control.* have any effect, except that
+ * {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} may be used by the camera
+ * device to select post-processing values for processing
+ * blocks that do not allow for manual control, or are not
+ * exposed by the camera API.</p>
+ * <p>However, the camera device's 3A routines may continue to
+ * collect statistics and update their internal state so that
+ * when control is switched to AUTO mode, good control values
+ * can be immediately applied.</p>
+ *
+ * @see CaptureRequest#CONTROL_CAPTURE_INTENT
* @see CaptureRequest#CONTROL_MODE
*/
public static final int CONTROL_MODE_OFF = 0;
/**
- * <p>Use settings for each individual 3A routine.
- * Manual control of capture parameters is disabled. All
+ * <p>Use settings for each individual 3A routine.</p>
+ * <p>Manual control of capture parameters is disabled. All
* controls in android.control.* besides sceneMode take
- * effect</p>
+ * effect.</p>
* @see CaptureRequest#CONTROL_MODE
*/
public static final int CONTROL_MODE_AUTO = 1;
/**
- * <p>Use specific scene mode. Enabling this disables
- * control.aeMode, control.awbMode and control.afMode
- * controls; the camera device will ignore those settings while
- * USE_SCENE_MODE is active (except for FACE_PRIORITY
- * scene mode). Other control entries are still active.
- * This setting can only be used if scene mode is supported
- * (i.e. {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes} contain some modes
- * other than DISABLED).</p>
+ * <p>Use a specific scene mode.</p>
+ * <p>Enabling this disables control.aeMode, control.awbMode and
+ * control.afMode controls; the camera device will ignore
+ * those settings while USE_SCENE_MODE is active (except for
+ * FACE_PRIORITY scene mode). Other control entries are still
+ * active. This setting can only be used if scene mode is
+ * supported (i.e. {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}
+ * contain some modes other than DISABLED).</p>
*
* @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
* @see CaptureRequest#CONTROL_MODE
@@ -1119,7 +1248,12 @@
/**
* <p>Same as OFF mode, except that this capture will not be
* used by camera device background auto-exposure, auto-white balance and
- * auto-focus algorithms to update their statistics.</p>
+ * auto-focus algorithms (3A) to update their statistics.</p>
+ * <p>Specifically, the 3A routines are locked to the last
+ * values set from a request with AUTO, OFF, or
+ * USE_SCENE_MODE, and any statistics or state updates
+ * collected from manual captures with OFF_KEEP_STATE will be
+ * discarded by the camera device.</p>
* @see CaptureRequest#CONTROL_MODE
*/
public static final int CONTROL_MODE_OFF_KEEP_STATE = 3;
@@ -1137,8 +1271,9 @@
/**
* <p>If face detection support exists, use face
* detection data for auto-focus, auto-white balance, and
- * auto-exposure routines. If face detection statistics are
- * disabled (i.e. {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} is set to OFF),
+ * auto-exposure routines.</p>
+ * <p>If face detection statistics are disabled
+ * (i.e. {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} is set to OFF),
* this should still operate correctly (but will not return
* face detection statistics to the framework).</p>
* <p>Unlike the other scene modes, {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode},
@@ -1154,8 +1289,8 @@
public static final int CONTROL_SCENE_MODE_FACE_PRIORITY = 1;
/**
- * <p>Optimized for photos of quickly moving objects.
- * Similar to SPORTS.</p>
+ * <p>Optimized for photos of quickly moving objects.</p>
+ * <p>Similar to SPORTS.</p>
* @see CaptureRequest#CONTROL_SCENE_MODE
*/
public static final int CONTROL_SCENE_MODE_ACTION = 2;
@@ -1224,8 +1359,8 @@
public static final int CONTROL_SCENE_MODE_FIREWORKS = 12;
/**
- * <p>Optimized for photos of quickly moving people.
- * Similar to ACTION.</p>
+ * <p>Optimized for photos of quickly moving people.</p>
+ * <p>Similar to ACTION.</p>
* @see CaptureRequest#CONTROL_SCENE_MODE
*/
public static final int CONTROL_SCENE_MODE_SPORTS = 13;
@@ -1257,11 +1392,13 @@
//
/**
+ * <p>Video stabilization is disabled.</p>
* @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
*/
public static final int CONTROL_VIDEO_STABILIZATION_MODE_OFF = 0;
/**
+ * <p>Video stabilization is enabled.</p>
* @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
*/
public static final int CONTROL_VIDEO_STABILIZATION_MODE_ON = 1;
@@ -1271,21 +1408,20 @@
//
/**
- * <p>No edge enhancement is applied</p>
+ * <p>No edge enhancement is applied.</p>
* @see CaptureRequest#EDGE_MODE
*/
public static final int EDGE_MODE_OFF = 0;
/**
- * <p>Must not slow down frame rate relative to sensor
+ * <p>Apply edge enhancement at a quality level that does not slow down frame rate relative to sensor
* output</p>
* @see CaptureRequest#EDGE_MODE
*/
public static final int EDGE_MODE_FAST = 1;
/**
- * <p>Frame rate may be reduced by high
- * quality</p>
+ * <p>Apply high-quality edge enhancement, at a cost of reducing output frame rate.</p>
* @see CaptureRequest#EDGE_MODE
*/
public static final int EDGE_MODE_HIGH_QUALITY = 2;
@@ -1318,10 +1454,10 @@
//
/**
+ * <p>No hot pixel correction is applied.</p>
* <p>The frame rate must not be reduced relative to sensor raw output
* for this option.</p>
- * <p>No hot pixel correction is applied.
- * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
+ * <p>The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
* @see CaptureRequest#HOT_PIXEL_MODE
@@ -1329,10 +1465,9 @@
public static final int HOT_PIXEL_MODE_OFF = 0;
/**
- * <p>The frame rate must not be reduced relative to sensor raw output
- * for this option.</p>
- * <p>Hot pixel correction is applied.
- * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
+ * <p>Hot pixel correction is applied, without reducing frame
+ * rate relative to sensor raw output.</p>
+ * <p>The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
* @see CaptureRequest#HOT_PIXEL_MODE
@@ -1340,10 +1475,9 @@
public static final int HOT_PIXEL_MODE_FAST = 1;
/**
- * <p>The frame rate may be reduced relative to sensor raw output
- * for this option.</p>
- * <p>A high-quality hot pixel correction is applied.
- * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
+ * <p>High-quality hot pixel correction is applied, at a cost
+ * of reducing frame rate relative to sensor raw output.</p>
+ * <p>The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
* @see CaptureRequest#HOT_PIXEL_MODE
@@ -1371,21 +1505,21 @@
//
/**
- * <p>No noise reduction is applied</p>
+ * <p>No noise reduction is applied.</p>
* @see CaptureRequest#NOISE_REDUCTION_MODE
*/
public static final int NOISE_REDUCTION_MODE_OFF = 0;
/**
- * <p>Must not slow down frame rate relative to sensor
- * output</p>
+ * <p>Noise reduction is applied without reducing frame rate relative to sensor
+ * output.</p>
* @see CaptureRequest#NOISE_REDUCTION_MODE
*/
public static final int NOISE_REDUCTION_MODE_FAST = 1;
/**
- * <p>May slow down frame rate to provide highest
- * quality</p>
+ * <p>High-quality noise reduction is applied, at the cost of reducing frame rate
+ * relative to sensor output.</p>
* @see CaptureRequest#NOISE_REDUCTION_MODE
*/
public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2;
@@ -1395,8 +1529,9 @@
//
/**
- * <p>Default. No test pattern mode is used, and the camera
+ * <p>No test pattern mode is used, and the camera
* device returns captures from the image sensor.</p>
+ * <p>This is the default if the key is not set.</p>
* @see CaptureRequest#SENSOR_TEST_PATTERN_MODE
*/
public static final int SENSOR_TEST_PATTERN_MODE_OFF = 0;
@@ -1500,19 +1635,21 @@
//
/**
- * <p>No lens shading correction is applied</p>
+ * <p>No lens shading correction is applied.</p>
* @see CaptureRequest#SHADING_MODE
*/
public static final int SHADING_MODE_OFF = 0;
/**
- * <p>Must not slow down frame rate relative to sensor raw output</p>
+ * <p>Apply lens shading corrections, without slowing
+ * frame rate relative to sensor raw output</p>
* @see CaptureRequest#SHADING_MODE
*/
public static final int SHADING_MODE_FAST = 1;
/**
- * <p>Frame rate may be reduced by high quality</p>
+ * <p>Apply high-quality lens shading correction, at the
+ * cost of reduced frame rate.</p>
* @see CaptureRequest#SHADING_MODE
*/
public static final int SHADING_MODE_HIGH_QUALITY = 2;
@@ -1522,20 +1659,28 @@
//
/**
+ * <p>Do not include face detection statistics in capture
+ * results.</p>
* @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
*/
public static final int STATISTICS_FACE_DETECT_MODE_OFF = 0;
/**
- * <p>Optional Return rectangle and confidence
- * only</p>
+ * <p>Return face rectangle and confidence values only.</p>
+ * <p>In this mode, only android.statistics.faceRectangles and
+ * android.statistics.faceScores outputs are valid.</p>
* @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
*/
public static final int STATISTICS_FACE_DETECT_MODE_SIMPLE = 1;
/**
- * <p>Optional Return all face
- * metadata</p>
+ * <p>Return all face
+ * metadata.</p>
+ * <p>In this mode,
+ * android.statistics.faceRectangles,
+ * android.statistics.faceScores,
+ * android.statistics.faceIds, and
+ * android.statistics.faceLandmarks outputs are valid.</p>
* @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
*/
public static final int STATISTICS_FACE_DETECT_MODE_FULL = 2;
@@ -1545,11 +1690,13 @@
//
/**
+ * <p>Do not include a lens shading map in the capture result.</p>
* @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
*/
public static final int STATISTICS_LENS_SHADING_MAP_MODE_OFF = 0;
/**
+ * <p>Include a lens shading map in the capture result.</p>
* @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
*/
public static final int STATISTICS_LENS_SHADING_MAP_MODE_ON = 1;
@@ -1573,15 +1720,15 @@
public static final int TONEMAP_MODE_CONTRAST_CURVE = 0;
/**
- * <p>Advanced gamma mapping and color enhancement may be applied.</p>
- * <p>Should not slow down frame rate relative to raw sensor output.</p>
+ * <p>Advanced gamma mapping and color enhancement may be applied, without
+ * reducing frame rate compared to raw sensor output.</p>
* @see CaptureRequest#TONEMAP_MODE
*/
public static final int TONEMAP_MODE_FAST = 1;
/**
- * <p>Advanced gamma mapping and color enhancement may be applied.</p>
- * <p>May slow down frame rate relative to raw sensor output.</p>
+ * <p>High-quality gamma mapping and color enhancement will be applied, at
+ * the cost of reduced frame rate compared to raw sensor output.</p>
* @see CaptureRequest#TONEMAP_MODE
*/
public static final int TONEMAP_MODE_HIGH_QUALITY = 2;
@@ -1591,7 +1738,8 @@
//
/**
- * <p>AE is off or recently reset. When a camera device is opened, it starts in
+ * <p>AE is off or recently reset.</p>
+ * <p>When a camera device is opened, it starts in
* this state. This is a transient state, the camera device may skip reporting
* this state in capture result.</p>
* @see CaptureResult#CONTROL_AE_STATE
@@ -1600,7 +1748,8 @@
/**
* <p>AE doesn't yet have a good set of control values
- * for the current scene. This is a transient state, the camera device may skip
+ * for the current scene.</p>
+ * <p>This is a transient state, the camera device may skip
* reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AE_STATE
*/
@@ -1629,11 +1778,13 @@
/**
* <p>AE has been asked to do a precapture sequence
- * (through the {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} START),
- * and is currently executing it. Once PRECAPTURE
- * completes, AE will transition to CONVERGED or
- * FLASH_REQUIRED as appropriate. This is a transient state, the
- * camera device may skip reporting this state in capture result.</p>
+ * and is currently executing it.</p>
+ * <p>Precapture can be triggered through setting
+ * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} to START.</p>
+ * <p>Once PRECAPTURE completes, AE will transition to CONVERGED
+ * or FLASH_REQUIRED as appropriate. This is a transient
+ * state, the camera device may skip reporting this state in
+ * capture result.</p>
*
* @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
* @see CaptureResult#CONTROL_AE_STATE
@@ -1645,61 +1796,78 @@
//
/**
- * <p>AF off or has not yet tried to scan/been asked
- * to scan. When a camera device is opened, it starts in
- * this state. This is a transient state, the camera device may
- * skip reporting this state in capture result.</p>
+ * <p>AF is off or has not yet tried to scan/been asked
+ * to scan.</p>
+ * <p>When a camera device is opened, it starts in this
+ * state. This is a transient state, the camera device may
+ * skip reporting this state in capture
+ * result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_INACTIVE = 0;
/**
- * <p>if CONTINUOUS_* modes are supported. AF is
- * currently doing an AF scan initiated by a continuous
- * autofocus mode. This is a transient state, the camera device may
- * skip reporting this state in capture result.</p>
+ * <p>AF is currently performing an AF scan initiated the
+ * camera device in a continuous autofocus mode.</p>
+ * <p>Only used by CONTINUOUS_* AF modes. This is a transient
+ * state, the camera device may skip reporting this state in
+ * capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_PASSIVE_SCAN = 1;
/**
- * <p>if CONTINUOUS_* modes are supported. AF currently
- * believes it is in focus, but may restart scanning at
- * any time. This is a transient state, the camera device may skip
- * reporting this state in capture result.</p>
+ * <p>AF currently believes it is in focus, but may
+ * restart scanning at any time.</p>
+ * <p>Only used by CONTINUOUS_* AF modes. This is a transient
+ * state, the camera device may skip reporting this state in
+ * capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_PASSIVE_FOCUSED = 2;
/**
- * <p>if AUTO or MACRO modes are supported. AF is doing
- * an AF scan because it was triggered by AF trigger. This is a
- * transient state, the camera device may skip reporting
- * this state in capture result.</p>
+ * <p>AF is performing an AF scan because it was
+ * triggered by AF trigger.</p>
+ * <p>Only used by AUTO or MACRO AF modes. This is a transient
+ * state, the camera device may skip reporting this state in
+ * capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_ACTIVE_SCAN = 3;
/**
- * <p>if any AF mode besides OFF is supported. AF
- * believes it is focused correctly and is
- * locked.</p>
+ * <p>AF believes it is focused correctly and has locked
+ * focus.</p>
+ * <p>This state is reached only after an explicit START AF trigger has been
+ * sent ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}), when good focus has been obtained.</p>
+ * <p>The lens will remain stationary until the AF mode ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) is changed or
+ * a new AF trigger is sent to the camera device ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}).</p>
+ *
+ * @see CaptureRequest#CONTROL_AF_MODE
+ * @see CaptureRequest#CONTROL_AF_TRIGGER
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_FOCUSED_LOCKED = 4;
/**
- * <p>if any AF mode besides OFF is supported. AF has
- * failed to focus successfully and is
- * locked.</p>
+ * <p>AF has failed to focus successfully and has locked
+ * focus.</p>
+ * <p>This state is reached only after an explicit START AF trigger has been
+ * sent ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}), when good focus cannot be obtained.</p>
+ * <p>The lens will remain stationary until the AF mode ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) is changed or
+ * a new AF trigger is sent to the camera device ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}).</p>
+ *
+ * @see CaptureRequest#CONTROL_AF_MODE
+ * @see CaptureRequest#CONTROL_AF_TRIGGER
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_NOT_FOCUSED_LOCKED = 5;
/**
- * <p>if CONTINUOUS_* modes are supported. AF finished a
- * passive scan without finding focus, and may restart
- * scanning at any time. This is a transient state, the camera
+ * <p>AF finished a passive scan without finding focus,
+ * and may restart scanning at any time.</p>
+ * <p>Only used by CONTINUOUS_* AF modes. This is a transient state, the camera
* device may skip reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
@@ -1710,16 +1878,19 @@
//
/**
- * <p>AWB is not in auto mode. When a camera device is opened, it
- * starts in this state. This is a transient state, the camera device may
- * skip reporting this state in capture result.</p>
+ * <p>AWB is not in auto mode, or has not yet started metering.</p>
+ * <p>When a camera device is opened, it starts in this
+ * state. This is a transient state, the camera device may
+ * skip reporting this state in capture
+ * result.</p>
* @see CaptureResult#CONTROL_AWB_STATE
*/
public static final int CONTROL_AWB_STATE_INACTIVE = 0;
/**
* <p>AWB doesn't yet have a good set of control
- * values for the current scene. This is a transient state, the camera device
+ * values for the current scene.</p>
+ * <p>This is a transient state, the camera device
* may skip reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AWB_STATE
*/
@@ -1767,8 +1938,9 @@
public static final int FLASH_STATE_FIRED = 3;
/**
- * <p>Flash partially illuminated this frame. This is usually due to the next
- * or previous frame having the flash fire, and the flash spilling into this capture
+ * <p>Flash partially illuminated this frame.</p>
+ * <p>This is usually due to the next or previous frame having
+ * the flash fire, and the flash spilling into this capture
* due to hardware limitations.</p>
* @see CaptureResult#FLASH_STATE
*/
@@ -1791,8 +1963,10 @@
public static final int LENS_STATE_STATIONARY = 0;
/**
- * <p>Any of the lens parameters ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance},
- * {@link CaptureRequest#LENS_FILTER_DENSITY android.lens.filterDensity} or {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) is changing.</p>
+ * <p>One or several of the lens parameters
+ * ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance},
+ * {@link CaptureRequest#LENS_FILTER_DENSITY android.lens.filterDensity} or {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) is
+ * currently changing.</p>
*
* @see CaptureRequest#LENS_APERTURE
* @see CaptureRequest#LENS_FILTER_DENSITY
@@ -1807,16 +1981,22 @@
//
/**
+ * <p>The camera device does not detect any flickering illumination
+ * in the current scene.</p>
* @see CaptureResult#STATISTICS_SCENE_FLICKER
*/
public static final int STATISTICS_SCENE_FLICKER_NONE = 0;
/**
+ * <p>The camera device detects illumination flickering at 50Hz
+ * in the current scene.</p>
* @see CaptureResult#STATISTICS_SCENE_FLICKER
*/
public static final int STATISTICS_SCENE_FLICKER_50HZ = 1;
/**
+ * <p>The camera device detects illumination flickering at 60Hz
+ * in the current scene.</p>
* @see CaptureResult#STATISTICS_SCENE_FLICKER
*/
public static final int STATISTICS_SCENE_FLICKER_60HZ = 2;
@@ -1826,8 +2006,8 @@
//
/**
- * <p>The current result is not yet fully synchronized to any request.
- * Synchronization is in progress, and reading metadata from this
+ * <p>The current result is not yet fully synchronized to any request.</p>
+ * <p>Synchronization is in progress, and reading metadata from this
* result may include a mix of data that have taken effect since the
* last synchronization time.</p>
* <p>In some future result, within {@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} frames,
@@ -1842,10 +2022,10 @@
public static final int SYNC_FRAME_NUMBER_CONVERGING = -1;
/**
- * <p>The current result's synchronization status is unknown. The
- * result may have already converged, or it may be in progress.
- * Reading from this result may include some mix of settings from
- * past requests.</p>
+ * <p>The current result's synchronization status is unknown.</p>
+ * <p>The result may have already converged, or it may be in
+ * progress. Reading from this result may include some mix
+ * of settings from past requests.</p>
* <p>After a settings change, the new settings will eventually all
* take effect for the output buffers and results. However, this
* value will not change when that happens. Altering settings
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index d4dfdd5..2cfb611 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -43,14 +43,14 @@
* <p>CaptureRequests can be created by using a {@link Builder} instance,
* obtained by calling {@link CameraDevice#createCaptureRequest}</p>
*
- * <p>CaptureRequests are given to {@link CameraDevice#capture} or
- * {@link CameraDevice#setRepeatingRequest} to capture images from a camera.</p>
+ * <p>CaptureRequests are given to {@link CameraCaptureSession#capture} or
+ * {@link CameraCaptureSession#setRepeatingRequest} to capture images from a camera.</p>
*
* <p>Each request can specify a different subset of target Surfaces for the
* camera to send the captured data to. All the surfaces used in a request must
* be part of the surface list given to the last call to
- * {@link CameraDevice#configureOutputs}, when the request is submitted to the
- * camera device.</p>
+ * {@link CameraDevice#createCaptureSession}, when the request is submitted to the
+ * session.</p>
*
* <p>For example, a request meant for repeating preview might only include the
* Surface for the preview SurfaceView or SurfaceTexture, while a
@@ -357,11 +357,11 @@
* request fields to one of the templates defined in {@link CameraDevice}.
*
* @see CameraDevice#createCaptureRequest
- * @see #TEMPLATE_PREVIEW
- * @see #TEMPLATE_RECORD
- * @see #TEMPLATE_STILL_CAPTURE
- * @see #TEMPLATE_VIDEO_SNAPSHOT
- * @see #TEMPLATE_MANUAL
+ * @see CameraDevice#TEMPLATE_PREVIEW
+ * @see CameraDevice#TEMPLATE_RECORD
+ * @see CameraDevice#TEMPLATE_STILL_CAPTURE
+ * @see CameraDevice#TEMPLATE_VIDEO_SNAPSHOT
+ * @see CameraDevice#TEMPLATE_MANUAL
*/
public final static class Builder {
@@ -381,7 +381,7 @@
* <p>Add a surface to the list of targets for this request</p>
*
* <p>The Surface added must be one of the surfaces included in the most
- * recent call to {@link CameraDevice#configureOutputs}, when the
+ * recent call to {@link CameraDevice#createCaptureSession}, when the
* request is given to the camera device.</p>
*
* <p>Adding a target more than once has no effect.</p>
@@ -473,7 +473,7 @@
/**
* <p>The mode control selects how the image data is converted from the
* sensor's native color into linear sRGB color.</p>
- * <p>When auto-white balance is enabled with {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, this
+ * <p>When auto-white balance (AWB) is enabled with {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, this
* control is overridden by the AWB routine. When AWB is disabled, the
* application controls how the color mapping is performed.</p>
* <p>We define the expected processing pipeline below. For consistency
@@ -524,7 +524,7 @@
/**
* <p>A color transform matrix to use to transform
- * from sensor RGB color space to output linear sRGB color space</p>
+ * from sensor RGB color space to output linear sRGB color space.</p>
* <p>This matrix is either set by the camera device when the request
* {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not TRANSFORM_MATRIX, or
* directly by the application in the request when the
@@ -600,13 +600,17 @@
new Key<Integer>("android.control.aeAntibandingMode", int.class);
/**
- * <p>Adjustment to AE target image
- * brightness</p>
- * <p>For example, if EV step is 0.333, '6' will mean an
- * exposure compensation of +2 EV; -3 will mean an exposure
- * compensation of -1 EV. Note that this control will only be effective
- * if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF. This control will take effect even when
- * {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} <code>== true</code>.</p>
+ * <p>Adjustment to auto-exposure (AE) target image
+ * brightness.</p>
+ * <p>The adjustment is measured as a count of steps, with the
+ * step size defined by {@link CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP android.control.aeCompensationStep} and the
+ * allowed range by {@link CameraCharacteristics#CONTROL_AE_COMPENSATION_RANGE android.control.aeCompensationRange}.</p>
+ * <p>For example, if the exposure value (EV) step is 0.333, '6'
+ * will mean an exposure compensation of +2 EV; -3 will mean an
+ * exposure compensation of -1 EV. One EV represents a doubling
+ * of image brightness. Note that this control will only be
+ * effective if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF. This control
+ * will take effect even when {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} <code>== true</code>.</p>
* <p>In the event of exposure compensation value being changed, camera device
* may take several frames to reach the newly requested exposure target.
* During that time, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} field will be in the SEARCHING
@@ -614,6 +618,8 @@
* change from SEARCHING to either CONVERGED, LOCKED (if AE lock is enabled), or
* FLASH_REQUIRED (if the scene is too dark for still capture).</p>
*
+ * @see CameraCharacteristics#CONTROL_AE_COMPENSATION_RANGE
+ * @see CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP
* @see CaptureRequest#CONTROL_AE_LOCK
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureResult#CONTROL_AE_STATE
@@ -622,7 +628,7 @@
new Key<Integer>("android.control.aeExposureCompensation", int.class);
/**
- * <p>Whether AE is currently locked to its latest
+ * <p>Whether auto-exposure (AE) is currently locked to its latest
* calculated values.</p>
* <p>Note that even when AE is locked, the flash may be
* fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
@@ -711,9 +717,9 @@
/**
* <p>Range over which fps can be adjusted to
- * maintain exposure</p>
- * <p>Only constrains AE algorithm, not manual control
- * of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}</p>
+ * maintain exposure.</p>
+ * <p>Only constrains auto-exposure (AE) algorithm, not
+ * manual control of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}</p>
*
* @see CaptureRequest#SENSOR_EXPOSURE_TIME
*/
@@ -727,9 +733,18 @@
* included at all in the request settings. When included and
* set to START, the camera device will trigger the autoexposure
* precapture metering sequence.</p>
- * <p>The effect of AE precapture trigger depends on the current
- * AE mode and state; see {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture
- * state transition details.</p>
+ * <p>The precapture sequence should triggered before starting a
+ * high-quality still capture for final metering decisions to
+ * be made, and for firing pre-capture flash pulses to estimate
+ * scene brightness and required final capture flash power, when
+ * the flash is enabled.</p>
+ * <p>Normally, this entry should be set to START for only a
+ * single request, and the application should wait until the
+ * sequence completes before starting a new one.</p>
+ * <p>The exact effect of auto-exposure (AE) precapture trigger
+ * depends on the current AE mode and state; see
+ * {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture state transition
+ * details.</p>
*
* @see CaptureResult#CONTROL_AE_STATE
* @see #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE
@@ -739,8 +754,8 @@
new Key<Integer>("android.control.aePrecaptureTrigger", int.class);
/**
- * <p>Whether AF is currently enabled, and what
- * mode it is set to</p>
+ * <p>Whether auto-focus (AF) is currently enabled, and what
+ * mode it is set to.</p>
* <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO and the lens is not fixed focus
* (i.e. <code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} > 0</code>).</p>
* <p>If the lens is controlled by the camera device auto-focus algorithm,
@@ -793,7 +808,11 @@
* autofocus algorithm. If autofocus is disabled, this trigger has no effect.</p>
* <p>When set to CANCEL, the camera device will cancel any active trigger,
* and return to its initial AF state.</p>
- * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what that means for each AF mode.</p>
+ * <p>Generally, applications should set this entry to START or CANCEL for only a
+ * single capture, and then return it to IDLE (or not set at all). Specifying
+ * START for multiple captures in a row means restarting the AF operation over
+ * and over again.</p>
+ * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what the trigger means for each AF mode.</p>
*
* @see CaptureResult#CONTROL_AF_STATE
* @see #CONTROL_AF_TRIGGER_IDLE
@@ -804,31 +823,37 @@
new Key<Integer>("android.control.afTrigger", int.class);
/**
- * <p>Whether AWB is currently locked to its
+ * <p>Whether auto-white balance (AWB) is currently locked to its
* latest calculated values.</p>
- * <p>Note that AWB lock is only meaningful for AUTO
- * mode; in other modes, AWB is already fixed to a specific
- * setting.</p>
+ * <p>Note that AWB lock is only meaningful when
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} is in the AUTO mode; in other modes,
+ * AWB is already fixed to a specific setting.</p>
+ *
+ * @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final Key<Boolean> CONTROL_AWB_LOCK =
new Key<Boolean>("android.control.awbLock", boolean.class);
/**
- * <p>Whether AWB is currently setting the color
+ * <p>Whether auto-white balance (AWB) is currently setting the color
* transform fields, and what its illumination target
* is.</p>
* <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is AUTO.</p>
- * <p>When set to the ON mode, the camera device's auto white balance
+ * <p>When set to the ON mode, the camera device's auto-white balance
* routine is enabled, overriding the application's selected
* {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
* {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
- * <p>When set to the OFF mode, the camera device's auto white balance
+ * <p>When set to the OFF mode, the camera device's auto-white balance
* routine is disabled. The application manually controls the white
* balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}
* and {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
- * <p>When set to any other modes, the camera device's auto white balance
- * routine is disabled. The camera device uses each particular illumination
- * target for white balance adjustment.</p>
+ * <p>When set to any other modes, the camera device's auto-white
+ * balance routine is disabled. The camera device uses each
+ * particular illumination target for white balance
+ * adjustment. The application's values for
+ * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform},
+ * {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
+ * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} are ignored.</p>
*
* @see CaptureRequest#COLOR_CORRECTION_GAINS
* @see CaptureRequest#COLOR_CORRECTION_MODE
@@ -879,8 +904,8 @@
* strategy.</p>
* <p>This control (except for MANUAL) is only effective if
* <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
- * <p>ZERO_SHUTTER_LAG must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
- * contains ZSL. MANUAL must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+ * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+ * contains ZSL. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
* contains MANUAL_SENSOR.</p>
*
* @see CaptureRequest#CONTROL_MODE
@@ -955,7 +980,9 @@
* <p>This is the mode that that is active when
* <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code>. Aside from FACE_PRIORITY,
* these modes will disable {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode},
- * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.</p>
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.
+ * The scene modes available for a given camera device are listed in
+ * {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}.</p>
* <p>The interpretation and implementation of these scene modes is left
* to the implementor of the camera device. Their behavior will not be
* consistent across all devices, and any given device may only implement
@@ -963,6 +990,7 @@
*
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_AF_MODE
+ * @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
* @see CaptureRequest#CONTROL_AWB_MODE
* @see CaptureRequest#CONTROL_MODE
* @see #CONTROL_SCENE_MODE_DISABLED
@@ -988,11 +1016,21 @@
/**
* <p>Whether video stabilization is
- * active</p>
+ * active.</p>
+ * <p>Video stabilization automatically translates and scales images from the camera
+ * in order to stabilize motion between consecutive frames.</p>
* <p>If enabled, video stabilization can modify the
- * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream
- * stabilized</p>
+ * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream stabilized.</p>
+ * <p>Switching between different video stabilization modes may take several frames
+ * to initialize, the camera device will report the current mode in capture result
+ * metadata. For example, When "ON" mode is requested, the video stabilization modes
+ * in the first several capture results may still be "OFF", and it will become "ON"
+ * when the initialization is done.</p>
+ * <p>If a camera device supports both this mode and OIS ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}),
+ * turning both modes on may produce undesirable interaction, so it is recommended not to
+ * enable both at the same time.</p>
*
+ * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
* @see CaptureRequest#SCALER_CROP_REGION
* @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF
* @see #CONTROL_VIDEO_STABILIZATION_MODE_ON
@@ -1030,7 +1068,7 @@
* <p>When set to OFF, the camera device will not fire flash for this capture.</p>
* <p>When set to SINGLE, the camera device will fire flash regardless of the camera
* device's auto-exposure routine's result. When used in still capture case, this
- * control should be used along with AE precapture metering sequence
+ * control should be used along with auto-exposure (AE) precapture metering sequence
* ({@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}), otherwise, the image may be incorrectly exposed.</p>
* <p>When set to TORCH, the flash will be on continuously. This mode can be used
* for use cases such as preview, auto-focus assist, still capture, or video recording.</p>
@@ -1102,21 +1140,21 @@
/**
* <p>Compression quality of the final JPEG
- * image</p>
- * <p>85-95 is typical usage range</p>
+ * image.</p>
+ * <p>85-95 is typical usage range.</p>
*/
public static final Key<Byte> JPEG_QUALITY =
new Key<Byte>("android.jpeg.quality", byte.class);
/**
* <p>Compression quality of JPEG
- * thumbnail</p>
+ * thumbnail.</p>
*/
public static final Key<Byte> JPEG_THUMBNAIL_QUALITY =
new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
/**
- * <p>Resolution of embedded JPEG thumbnail</p>
+ * <p>Resolution of embedded JPEG thumbnail.</p>
* <p>When set to (0, 0) value, the JPEG EXIF will not contain thumbnail,
* but the captured JPEG will still be a valid image.</p>
* <p>When a jpeg image capture is issued, the thumbnail size selected should have
@@ -1204,7 +1242,7 @@
/**
* <p>Distance to plane of sharpest focus,
- * measured from frontmost surface of the lens</p>
+ * measured from frontmost surface of the lens.</p>
* <p>0 means infinity focus. Used value will be clamped
* to [0, {@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance}].</p>
* <p>Like {@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, this setting won't be applied
@@ -1222,12 +1260,26 @@
/**
* <p>Sets whether the camera device uses optical image stabilization (OIS)
* when capturing images.</p>
- * <p>OIS is used to compensate for motion blur due to small movements of
- * the camera during capture. Unlike digital image stabilization, OIS makes
- * use of mechanical elements to stabilize the camera sensor, and thus
- * allows for longer exposure times before camera shake becomes
- * apparent.</p>
- * <p>This is not expected to be supported on most devices.</p>
+ * <p>OIS is used to compensate for motion blur due to small
+ * movements of the camera during capture. Unlike digital image
+ * stabilization ({@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode}), OIS
+ * makes use of mechanical elements to stabilize the camera
+ * sensor, and thus allows for longer exposure times before
+ * camera shake becomes apparent.</p>
+ * <p>Switching between different optical stabilization modes may take several
+ * frames to initialize, the camera device will report the current mode in
+ * capture result metadata. For example, When "ON" mode is requested, the
+ * optical stabilization modes in the first several capture results may still
+ * be "OFF", and it will become "ON" when the initialization is done.</p>
+ * <p>If a camera device supports both OIS and EIS ({@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode}),
+ * turning both modes on may produce undesirable interaction, so it is recommended not
+ * to enable both at the same time.</p>
+ * <p>Not all devices will support OIS; see
+ * {@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization} for
+ * available controls.</p>
+ *
+ * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
+ * @see CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION
* @see #LENS_OPTICAL_STABILIZATION_MODE_OFF
* @see #LENS_OPTICAL_STABILIZATION_MODE_ON
*/
@@ -1235,16 +1287,15 @@
new Key<Integer>("android.lens.opticalStabilizationMode", int.class);
/**
- * <p>Mode of operation for the noise reduction
- * algorithm</p>
+ * <p>Mode of operation for the noise reduction algorithm.</p>
* <p>Noise filtering control. OFF means no noise reduction
* will be applied by the camera device.</p>
- * <p>This must be set to a valid mode in
+ * <p>This must be set to a valid mode from
* {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes}.</p>
* <p>FAST/HIGH_QUALITY both mean camera device determined noise filtering
* will be applied. HIGH_QUALITY mode indicates that the camera device
* will use the highest-quality noise filtering algorithms,
- * even if it slows down capture rate. FAST means the camera device should not
+ * even if it slows down capture rate. FAST means the camera device will not
* slow down capture rate when applying noise filtering.</p>
*
* @see CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES
@@ -1265,40 +1316,39 @@
new Key<Integer>("android.request.id", int.class);
/**
- * <p>(x, y, width, height).</p>
- * <p>A rectangle with the top-level corner of (x,y) and size
- * (width, height). The region of the sensor that is used for
- * output. Each stream must use this rectangle to produce its
- * output, cropping to a smaller region if necessary to
- * maintain the stream's aspect ratio.</p>
- * <p>HAL2.x uses only (x, y, width)</p>
- * <p>The crop region is applied after the RAW to other color space (e.g. YUV)
- * conversion. Since raw streams (e.g. RAW16) don't have the conversion stage,
- * it is not croppable. The crop region will be ignored by raw streams.</p>
+ * <p>The region of the sensor to read out for this capture.</p>
+ * <p>The crop region coordinate system is based off
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being the
+ * top-left corner of the sensor active array.</p>
+ * <p>Output streams use this rectangle to produce their output,
+ * cropping to a smaller region if necessary to maintain the
+ * stream's aspect ratio, then scaling the sensor input to
+ * match the output's configured resolution.</p>
+ * <p>The crop region is applied after the RAW to other color
+ * space (e.g. YUV) conversion. Since raw streams
+ * (e.g. RAW16) don't have the conversion stage, they are not
+ * croppable. The crop region will be ignored by raw streams.</p>
* <p>For non-raw streams, any additional per-stream cropping will
* be done to maximize the final pixel area of the stream.</p>
* <p>For example, if the crop region is set to a 4:3 aspect
- * ratio, then 4:3 streams should use the exact crop
- * region. 16:9 streams should further crop vertically
+ * ratio, then 4:3 streams will use the exact crop
+ * region. 16:9 streams will further crop vertically
* (letterbox).</p>
* <p>Conversely, if the crop region is set to a 16:9, then 4:3
- * outputs should crop horizontally (pillarbox), and 16:9
- * streams should match exactly. These additional crops must
+ * outputs will crop horizontally (pillarbox), and 16:9
+ * streams will match exactly. These additional crops will
* be centered within the crop region.</p>
- * <p>The output streams must maintain square pixels at all
- * times, no matter what the relative aspect ratios of the
- * crop region and the stream are. Negative values for
- * corner are allowed for raw output if full pixel array is
- * larger than active pixel array. Width and height may be
- * rounded to nearest larger supportable width, especially
- * for raw output, where only a few fixed scales may be
- * possible. The width and height of the crop region cannot
- * be set to be smaller than floor( activeArraySize.width /
- * {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} ) and floor(
- * activeArraySize.height /
- * {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom}), respectively.</p>
+ * <p>The width and height of the crop region cannot
+ * be set to be smaller than
+ * <code>floor( activeArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code> and
+ * <code>floor( activeArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>, respectively.</p>
+ * <p>The camera device may adjust the crop region to account
+ * for rounding and other hardware requirements; the final
+ * crop region used will be included in the output capture
+ * result.</p>
*
* @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
*/
public static final Key<android.graphics.Rect> SCALER_CROP_REGION =
new Key<android.graphics.Rect>("android.scaler.cropRegion", android.graphics.Rect.class);
@@ -1391,12 +1441,20 @@
new Key<Long>("android.sensor.frameDuration", long.class);
/**
- * <p>Gain applied to image data. Must be
- * implemented through analog gain only if set to values
- * below 'maximum analog sensitivity'.</p>
- * <p>If the sensor can't apply this exact gain, it should lessen the
- * gain to the nearest possible value (rather than gain more).</p>
- * <p>ISO 12232:2006 REI method</p>
+ * <p>The amount of gain applied to sensor data
+ * before processing.</p>
+ * <p>The sensitivity is the standard ISO sensitivity value,
+ * as defined in ISO 12232:2006.</p>
+ * <p>The sensitivity must be within {@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}, and
+ * if if it less than {@link CameraCharacteristics#SENSOR_MAX_ANALOG_SENSITIVITY android.sensor.maxAnalogSensitivity}, the camera device
+ * is guaranteed to use only analog amplification for applying the gain.</p>
+ * <p>If the camera device cannot apply the exact sensitivity
+ * requested, it will reduce the gain to the nearest supported
+ * value. The final sensitivity used will be available in the
+ * output capture result.</p>
+ *
+ * @see CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE
+ * @see CameraCharacteristics#SENSOR_MAX_ANALOG_SENSITIVITY
*/
public static final Key<Integer> SENSOR_SENSITIVITY =
new Key<Integer>("android.sensor.sensitivity", int.class);
@@ -1421,7 +1479,7 @@
* <p>When enabled, the sensor sends a test pattern instead of
* doing a real exposure from the camera.</p>
* <p>When a test pattern is enabled, all manual sensor controls specified
- * by android.sensor.* should be ignored. All other controls should
+ * by android.sensor.* will be ignored. All other controls should
* work as normal.</p>
* <p>For example, if manual flash is enabled, flash firing should still
* occur (and that the test pattern remain unmodified, since the flash
@@ -1459,7 +1517,7 @@
* lens shading map data in android.statistics.lensShadingMap, with size specified
* by android.lens.info.shadingMapSize; the returned shading map data will be the one
* applied by the camera device for this capture request.</p>
- * <p>The shading map data may depend on the AE and AWB statistics, therefore the reliability
+ * <p>The shading map data may depend on the auto-exposure (AE) and AWB statistics, therefore the reliability
* of the map data may be affected by the AE and AWB algorithms. When AE and AWB are in
* AUTO modes({@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF and {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} <code>!=</code> OFF),
* to get best results, it is recommended that the applications wait for the AE and AWB to
@@ -1476,8 +1534,8 @@
new Key<Integer>("android.shading.mode", int.class);
/**
- * <p>State of the face detector
- * unit</p>
+ * <p>Control for the face detector
+ * unit.</p>
* <p>Whether face detection is enabled, and whether it
* should output just the basic fields or the full set of
* fields. Value must be one of the
@@ -1494,7 +1552,7 @@
/**
* <p>Operating mode for hotpixel map generation.</p>
* <p>If set to ON, a hotpixel map is returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.
- * If set to OFF, no hotpixel map should be returned.</p>
+ * If set to OFF, no hotpixel map will be returned.</p>
* <p>This must be set to a valid mode from {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES android.statistics.info.availableHotPixelMapModes}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
@@ -1507,7 +1565,7 @@
* <p>Whether the camera device will output the lens
* shading map in output result metadata.</p>
* <p>When set to ON,
- * android.statistics.lensShadingMap must be provided in
+ * android.statistics.lensShadingMap will be provided in
* the output result metadata.</p>
* @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
* @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 7d07c92..9097220 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -319,7 +319,7 @@
/**
* <p>The mode control selects how the image data is converted from the
* sensor's native color into linear sRGB color.</p>
- * <p>When auto-white balance is enabled with {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, this
+ * <p>When auto-white balance (AWB) is enabled with {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, this
* control is overridden by the AWB routine. When AWB is disabled, the
* application controls how the color mapping is performed.</p>
* <p>We define the expected processing pipeline below. For consistency
@@ -370,7 +370,7 @@
/**
* <p>A color transform matrix to use to transform
- * from sensor RGB color space to output linear sRGB color space</p>
+ * from sensor RGB color space to output linear sRGB color space.</p>
* <p>This matrix is either set by the camera device when the request
* {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not TRANSFORM_MATRIX, or
* directly by the application in the request when the
@@ -446,13 +446,17 @@
new Key<Integer>("android.control.aeAntibandingMode", int.class);
/**
- * <p>Adjustment to AE target image
- * brightness</p>
- * <p>For example, if EV step is 0.333, '6' will mean an
- * exposure compensation of +2 EV; -3 will mean an exposure
- * compensation of -1 EV. Note that this control will only be effective
- * if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF. This control will take effect even when
- * {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} <code>== true</code>.</p>
+ * <p>Adjustment to auto-exposure (AE) target image
+ * brightness.</p>
+ * <p>The adjustment is measured as a count of steps, with the
+ * step size defined by {@link CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP android.control.aeCompensationStep} and the
+ * allowed range by {@link CameraCharacteristics#CONTROL_AE_COMPENSATION_RANGE android.control.aeCompensationRange}.</p>
+ * <p>For example, if the exposure value (EV) step is 0.333, '6'
+ * will mean an exposure compensation of +2 EV; -3 will mean an
+ * exposure compensation of -1 EV. One EV represents a doubling
+ * of image brightness. Note that this control will only be
+ * effective if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF. This control
+ * will take effect even when {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} <code>== true</code>.</p>
* <p>In the event of exposure compensation value being changed, camera device
* may take several frames to reach the newly requested exposure target.
* During that time, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} field will be in the SEARCHING
@@ -460,6 +464,8 @@
* change from SEARCHING to either CONVERGED, LOCKED (if AE lock is enabled), or
* FLASH_REQUIRED (if the scene is too dark for still capture).</p>
*
+ * @see CameraCharacteristics#CONTROL_AE_COMPENSATION_RANGE
+ * @see CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP
* @see CaptureRequest#CONTROL_AE_LOCK
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureResult#CONTROL_AE_STATE
@@ -468,7 +474,7 @@
new Key<Integer>("android.control.aeExposureCompensation", int.class);
/**
- * <p>Whether AE is currently locked to its latest
+ * <p>Whether auto-exposure (AE) is currently locked to its latest
* calculated values.</p>
* <p>Note that even when AE is locked, the flash may be
* fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
@@ -557,9 +563,9 @@
/**
* <p>Range over which fps can be adjusted to
- * maintain exposure</p>
- * <p>Only constrains AE algorithm, not manual control
- * of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}</p>
+ * maintain exposure.</p>
+ * <p>Only constrains auto-exposure (AE) algorithm, not
+ * manual control of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}</p>
*
* @see CaptureRequest#SENSOR_EXPOSURE_TIME
*/
@@ -573,9 +579,18 @@
* included at all in the request settings. When included and
* set to START, the camera device will trigger the autoexposure
* precapture metering sequence.</p>
- * <p>The effect of AE precapture trigger depends on the current
- * AE mode and state; see {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture
- * state transition details.</p>
+ * <p>The precapture sequence should triggered before starting a
+ * high-quality still capture for final metering decisions to
+ * be made, and for firing pre-capture flash pulses to estimate
+ * scene brightness and required final capture flash power, when
+ * the flash is enabled.</p>
+ * <p>Normally, this entry should be set to START for only a
+ * single request, and the application should wait until the
+ * sequence completes before starting a new one.</p>
+ * <p>The exact effect of auto-exposure (AE) precapture trigger
+ * depends on the current AE mode and state; see
+ * {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture state transition
+ * details.</p>
*
* @see CaptureResult#CONTROL_AE_STATE
* @see #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE
@@ -585,7 +600,7 @@
new Key<Integer>("android.control.aePrecaptureTrigger", int.class);
/**
- * <p>Current state of AE algorithm</p>
+ * <p>Current state of the auto-exposure (AE) algorithm.</p>
* <p>Switching between or enabling AE modes ({@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}) always
* resets the AE state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
* or {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} if <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code> resets all
@@ -783,8 +798,8 @@
new Key<Integer>("android.control.aeState", int.class);
/**
- * <p>Whether AF is currently enabled, and what
- * mode it is set to</p>
+ * <p>Whether auto-focus (AF) is currently enabled, and what
+ * mode it is set to.</p>
* <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO and the lens is not fixed focus
* (i.e. <code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} > 0</code>).</p>
* <p>If the lens is controlled by the camera device auto-focus algorithm,
@@ -837,7 +852,11 @@
* autofocus algorithm. If autofocus is disabled, this trigger has no effect.</p>
* <p>When set to CANCEL, the camera device will cancel any active trigger,
* and return to its initial AF state.</p>
- * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what that means for each AF mode.</p>
+ * <p>Generally, applications should set this entry to START or CANCEL for only a
+ * single capture, and then return it to IDLE (or not set at all). Specifying
+ * START for multiple captures in a row means restarting the AF operation over
+ * and over again.</p>
+ * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what the trigger means for each AF mode.</p>
*
* @see CaptureResult#CONTROL_AF_STATE
* @see #CONTROL_AF_TRIGGER_IDLE
@@ -848,7 +867,7 @@
new Key<Integer>("android.control.afTrigger", int.class);
/**
- * <p>Current state of AF algorithm.</p>
+ * <p>Current state of auto-focus (AF) algorithm.</p>
* <p>Switching between or enabling AF modes ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) always
* resets the AF state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
* or {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} if <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code> resets all
@@ -1027,13 +1046,13 @@
* <td align="center">PASSIVE_SCAN</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Immediate trans. If focus is good, Lens now locked</td>
+ * <td align="center">Immediate transition, if focus is good. Lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_SCAN</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Immediate trans. if focus is bad, Lens now locked</td>
+ * <td align="center">Immediate transition, if focus is bad. Lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_SCAN</td>
@@ -1057,13 +1076,13 @@
* <td align="center">PASSIVE_FOCUSED</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Immediate trans. Lens now locked</td>
+ * <td align="center">Immediate transition, lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_UNFOCUSED</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Immediate trans. Lens now locked</td>
+ * <td align="center">Immediate transition, lens now locked</td>
* </tr>
* <tr>
* <td align="center">FOCUSED_LOCKED</td>
@@ -1130,13 +1149,13 @@
* <td align="center">PASSIVE_SCAN</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Eventual trans. once focus good, Lens now locked</td>
+ * <td align="center">Eventual transition once the focus is good. Lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_SCAN</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Eventual trans. if cannot focus, Lens now locked</td>
+ * <td align="center">Eventual transition if cannot find focus. Lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_SCAN</td>
@@ -1245,31 +1264,37 @@
new Key<Integer>("android.control.afState", int.class);
/**
- * <p>Whether AWB is currently locked to its
+ * <p>Whether auto-white balance (AWB) is currently locked to its
* latest calculated values.</p>
- * <p>Note that AWB lock is only meaningful for AUTO
- * mode; in other modes, AWB is already fixed to a specific
- * setting.</p>
+ * <p>Note that AWB lock is only meaningful when
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} is in the AUTO mode; in other modes,
+ * AWB is already fixed to a specific setting.</p>
+ *
+ * @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final Key<Boolean> CONTROL_AWB_LOCK =
new Key<Boolean>("android.control.awbLock", boolean.class);
/**
- * <p>Whether AWB is currently setting the color
+ * <p>Whether auto-white balance (AWB) is currently setting the color
* transform fields, and what its illumination target
* is.</p>
* <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is AUTO.</p>
- * <p>When set to the ON mode, the camera device's auto white balance
+ * <p>When set to the ON mode, the camera device's auto-white balance
* routine is enabled, overriding the application's selected
* {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
* {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
- * <p>When set to the OFF mode, the camera device's auto white balance
+ * <p>When set to the OFF mode, the camera device's auto-white balance
* routine is disabled. The application manually controls the white
* balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}
* and {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
- * <p>When set to any other modes, the camera device's auto white balance
- * routine is disabled. The camera device uses each particular illumination
- * target for white balance adjustment.</p>
+ * <p>When set to any other modes, the camera device's auto-white
+ * balance routine is disabled. The camera device uses each
+ * particular illumination target for white balance
+ * adjustment. The application's values for
+ * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform},
+ * {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
+ * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} are ignored.</p>
*
* @see CaptureRequest#COLOR_CORRECTION_GAINS
* @see CaptureRequest#COLOR_CORRECTION_MODE
@@ -1320,8 +1345,8 @@
* strategy.</p>
* <p>This control (except for MANUAL) is only effective if
* <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
- * <p>ZERO_SHUTTER_LAG must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
- * contains ZSL. MANUAL must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+ * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+ * contains ZSL. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
* contains MANUAL_SENSOR.</p>
*
* @see CaptureRequest#CONTROL_MODE
@@ -1338,7 +1363,7 @@
new Key<Integer>("android.control.captureIntent", int.class);
/**
- * <p>Current state of AWB algorithm</p>
+ * <p>Current state of auto-white balance (AWB) algorithm.</p>
* <p>Switching between or enabling AWB modes ({@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}) always
* resets the AWB state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
* or {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} if <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code> resets all
@@ -1526,7 +1551,9 @@
* <p>This is the mode that that is active when
* <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code>. Aside from FACE_PRIORITY,
* these modes will disable {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode},
- * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.</p>
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.
+ * The scene modes available for a given camera device are listed in
+ * {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}.</p>
* <p>The interpretation and implementation of these scene modes is left
* to the implementor of the camera device. Their behavior will not be
* consistent across all devices, and any given device may only implement
@@ -1534,6 +1561,7 @@
*
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_AF_MODE
+ * @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
* @see CaptureRequest#CONTROL_AWB_MODE
* @see CaptureRequest#CONTROL_MODE
* @see #CONTROL_SCENE_MODE_DISABLED
@@ -1559,11 +1587,21 @@
/**
* <p>Whether video stabilization is
- * active</p>
+ * active.</p>
+ * <p>Video stabilization automatically translates and scales images from the camera
+ * in order to stabilize motion between consecutive frames.</p>
* <p>If enabled, video stabilization can modify the
- * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream
- * stabilized</p>
+ * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream stabilized.</p>
+ * <p>Switching between different video stabilization modes may take several frames
+ * to initialize, the camera device will report the current mode in capture result
+ * metadata. For example, When "ON" mode is requested, the video stabilization modes
+ * in the first several capture results may still be "OFF", and it will become "ON"
+ * when the initialization is done.</p>
+ * <p>If a camera device supports both this mode and OIS ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}),
+ * turning both modes on may produce undesirable interaction, so it is recommended not to
+ * enable both at the same time.</p>
*
+ * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
* @see CaptureRequest#SCALER_CROP_REGION
* @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF
* @see #CONTROL_VIDEO_STABILIZATION_MODE_ON
@@ -1601,7 +1639,7 @@
* <p>When set to OFF, the camera device will not fire flash for this capture.</p>
* <p>When set to SINGLE, the camera device will fire flash regardless of the camera
* device's auto-exposure routine's result. When used in still capture case, this
- * control should be used along with AE precapture metering sequence
+ * control should be used along with auto-exposure (AE) precapture metering sequence
* ({@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}), otherwise, the image may be incorrectly exposed.</p>
* <p>When set to TORCH, the flash will be on continuously. This mode can be used
* for use cases such as preview, auto-focus assist, still capture, or video recording.</p>
@@ -1690,21 +1728,21 @@
/**
* <p>Compression quality of the final JPEG
- * image</p>
- * <p>85-95 is typical usage range</p>
+ * image.</p>
+ * <p>85-95 is typical usage range.</p>
*/
public static final Key<Byte> JPEG_QUALITY =
new Key<Byte>("android.jpeg.quality", byte.class);
/**
* <p>Compression quality of JPEG
- * thumbnail</p>
+ * thumbnail.</p>
*/
public static final Key<Byte> JPEG_THUMBNAIL_QUALITY =
new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
/**
- * <p>Resolution of embedded JPEG thumbnail</p>
+ * <p>Resolution of embedded JPEG thumbnail.</p>
* <p>When set to (0, 0) value, the JPEG EXIF will not contain thumbnail,
* but the captured JPEG will still be a valid image.</p>
* <p>When a jpeg image capture is issued, the thumbnail size selected should have
@@ -1792,7 +1830,7 @@
/**
* <p>Distance to plane of sharpest focus,
- * measured from frontmost surface of the lens</p>
+ * measured from frontmost surface of the lens.</p>
* <p>Should be zero for fixed-focus cameras</p>
*/
public static final Key<Float> LENS_FOCUS_DISTANCE =
@@ -1800,7 +1838,7 @@
/**
* <p>The range of scene distances that are in
- * sharp focus (depth of field)</p>
+ * sharp focus (depth of field).</p>
* <p>If variable focus not supported, can still report
* fixed depth of field range</p>
*/
@@ -1810,12 +1848,26 @@
/**
* <p>Sets whether the camera device uses optical image stabilization (OIS)
* when capturing images.</p>
- * <p>OIS is used to compensate for motion blur due to small movements of
- * the camera during capture. Unlike digital image stabilization, OIS makes
- * use of mechanical elements to stabilize the camera sensor, and thus
- * allows for longer exposure times before camera shake becomes
- * apparent.</p>
- * <p>This is not expected to be supported on most devices.</p>
+ * <p>OIS is used to compensate for motion blur due to small
+ * movements of the camera during capture. Unlike digital image
+ * stabilization ({@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode}), OIS
+ * makes use of mechanical elements to stabilize the camera
+ * sensor, and thus allows for longer exposure times before
+ * camera shake becomes apparent.</p>
+ * <p>Switching between different optical stabilization modes may take several
+ * frames to initialize, the camera device will report the current mode in
+ * capture result metadata. For example, When "ON" mode is requested, the
+ * optical stabilization modes in the first several capture results may still
+ * be "OFF", and it will become "ON" when the initialization is done.</p>
+ * <p>If a camera device supports both OIS and EIS ({@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode}),
+ * turning both modes on may produce undesirable interaction, so it is recommended not
+ * to enable both at the same time.</p>
+ * <p>Not all devices will support OIS; see
+ * {@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization} for
+ * available controls.</p>
+ *
+ * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
+ * @see CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION
* @see #LENS_OPTICAL_STABILIZATION_MODE_OFF
* @see #LENS_OPTICAL_STABILIZATION_MODE_ON
*/
@@ -1859,16 +1911,15 @@
new Key<Integer>("android.lens.state", int.class);
/**
- * <p>Mode of operation for the noise reduction
- * algorithm</p>
+ * <p>Mode of operation for the noise reduction algorithm.</p>
* <p>Noise filtering control. OFF means no noise reduction
* will be applied by the camera device.</p>
- * <p>This must be set to a valid mode in
+ * <p>This must be set to a valid mode from
* {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes}.</p>
* <p>FAST/HIGH_QUALITY both mean camera device determined noise filtering
* will be applied. HIGH_QUALITY mode indicates that the camera device
* will use the highest-quality noise filtering algorithms,
- * even if it slows down capture rate. FAST means the camera device should not
+ * even if it slows down capture rate. FAST means the camera device will not
* slow down capture rate when applying noise filtering.</p>
*
* @see CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES
@@ -1934,40 +1985,39 @@
new Key<Byte>("android.request.pipelineDepth", byte.class);
/**
- * <p>(x, y, width, height).</p>
- * <p>A rectangle with the top-level corner of (x,y) and size
- * (width, height). The region of the sensor that is used for
- * output. Each stream must use this rectangle to produce its
- * output, cropping to a smaller region if necessary to
- * maintain the stream's aspect ratio.</p>
- * <p>HAL2.x uses only (x, y, width)</p>
- * <p>The crop region is applied after the RAW to other color space (e.g. YUV)
- * conversion. Since raw streams (e.g. RAW16) don't have the conversion stage,
- * it is not croppable. The crop region will be ignored by raw streams.</p>
+ * <p>The region of the sensor to read out for this capture.</p>
+ * <p>The crop region coordinate system is based off
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with <code>(0, 0)</code> being the
+ * top-left corner of the sensor active array.</p>
+ * <p>Output streams use this rectangle to produce their output,
+ * cropping to a smaller region if necessary to maintain the
+ * stream's aspect ratio, then scaling the sensor input to
+ * match the output's configured resolution.</p>
+ * <p>The crop region is applied after the RAW to other color
+ * space (e.g. YUV) conversion. Since raw streams
+ * (e.g. RAW16) don't have the conversion stage, they are not
+ * croppable. The crop region will be ignored by raw streams.</p>
* <p>For non-raw streams, any additional per-stream cropping will
* be done to maximize the final pixel area of the stream.</p>
* <p>For example, if the crop region is set to a 4:3 aspect
- * ratio, then 4:3 streams should use the exact crop
- * region. 16:9 streams should further crop vertically
+ * ratio, then 4:3 streams will use the exact crop
+ * region. 16:9 streams will further crop vertically
* (letterbox).</p>
* <p>Conversely, if the crop region is set to a 16:9, then 4:3
- * outputs should crop horizontally (pillarbox), and 16:9
- * streams should match exactly. These additional crops must
+ * outputs will crop horizontally (pillarbox), and 16:9
+ * streams will match exactly. These additional crops will
* be centered within the crop region.</p>
- * <p>The output streams must maintain square pixels at all
- * times, no matter what the relative aspect ratios of the
- * crop region and the stream are. Negative values for
- * corner are allowed for raw output if full pixel array is
- * larger than active pixel array. Width and height may be
- * rounded to nearest larger supportable width, especially
- * for raw output, where only a few fixed scales may be
- * possible. The width and height of the crop region cannot
- * be set to be smaller than floor( activeArraySize.width /
- * {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} ) and floor(
- * activeArraySize.height /
- * {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom}), respectively.</p>
+ * <p>The width and height of the crop region cannot
+ * be set to be smaller than
+ * <code>floor( activeArraySize.width / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code> and
+ * <code>floor( activeArraySize.height / {@link CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM android.scaler.availableMaxDigitalZoom} )</code>, respectively.</p>
+ * <p>The camera device may adjust the crop region to account
+ * for rounding and other hardware requirements; the final
+ * crop region used will be included in the output capture
+ * result.</p>
*
* @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
*/
public static final Key<android.graphics.Rect> SCALER_CROP_REGION =
new Key<android.graphics.Rect>("android.scaler.cropRegion", android.graphics.Rect.class);
@@ -2060,21 +2110,42 @@
new Key<Long>("android.sensor.frameDuration", long.class);
/**
- * <p>Gain applied to image data. Must be
- * implemented through analog gain only if set to values
- * below 'maximum analog sensitivity'.</p>
- * <p>If the sensor can't apply this exact gain, it should lessen the
- * gain to the nearest possible value (rather than gain more).</p>
- * <p>ISO 12232:2006 REI method</p>
+ * <p>The amount of gain applied to sensor data
+ * before processing.</p>
+ * <p>The sensitivity is the standard ISO sensitivity value,
+ * as defined in ISO 12232:2006.</p>
+ * <p>The sensitivity must be within {@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}, and
+ * if if it less than {@link CameraCharacteristics#SENSOR_MAX_ANALOG_SENSITIVITY android.sensor.maxAnalogSensitivity}, the camera device
+ * is guaranteed to use only analog amplification for applying the gain.</p>
+ * <p>If the camera device cannot apply the exact sensitivity
+ * requested, it will reduce the gain to the nearest supported
+ * value. The final sensitivity used will be available in the
+ * output capture result.</p>
+ *
+ * @see CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE
+ * @see CameraCharacteristics#SENSOR_MAX_ANALOG_SENSITIVITY
*/
public static final Key<Integer> SENSOR_SENSITIVITY =
new Key<Integer>("android.sensor.sensitivity", int.class);
/**
* <p>Time at start of exposure of first
- * row</p>
- * <p>Monotonic, should be synced to other timestamps in
- * system</p>
+ * row of the image sensor active array, in nanoseconds.</p>
+ * <p>The timestamps are also included in all image
+ * buffers produced for the same capture, and will be identical
+ * on all the outputs.</p>
+ * <p>When {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION android.sensor.info.timestampCalibration} <code>==</code> UNCALIBRATED,
+ * the timestamps measure time since an unspecified starting point,
+ * and are monotonically increasing. They can be compared with the
+ * timestamps for other captures from the same camera device, but are
+ * not guaranteed to be comparable to any other time source.</p>
+ * <p>When {@link CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION android.sensor.info.timestampCalibration} <code>==</code> CALIBRATED,
+ * the timestamps measure time in the same timebase as
+ * android.os.SystemClock#elapsedRealtimeNanos(), and they can be
+ * compared to other timestamps from other subsystems that are using
+ * that base.</p>
+ *
+ * @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_CALIBRATION
*/
public static final Key<Long> SENSOR_TIMESTAMP =
new Key<Long>("android.sensor.timestamp", long.class);
@@ -2150,7 +2221,7 @@
* <p>When enabled, the sensor sends a test pattern instead of
* doing a real exposure from the camera.</p>
* <p>When a test pattern is enabled, all manual sensor controls specified
- * by android.sensor.* should be ignored. All other controls should
+ * by android.sensor.* will be ignored. All other controls should
* work as normal.</p>
* <p>For example, if manual flash is enabled, flash firing should still
* occur (and that the test pattern remain unmodified, since the flash
@@ -2167,6 +2238,20 @@
new Key<Integer>("android.sensor.testPatternMode", int.class);
/**
+ * <p>Duration between the start of first row exposure
+ * and the start of last row exposure.</p>
+ * <p>This is the exposure time skew (in the unit of nanosecond) between the first and
+ * last row exposure start times. The first row and the last row are the first
+ * and last rows inside of the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
+ * <p>For typical camera sensors that use rolling shutters, this is also equivalent
+ * to the frame readout time.</p>
+ *
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ */
+ public static final Key<Long> SENSOR_ROLLING_SHUTTER_SKEW =
+ new Key<Long>("android.sensor.rollingShutterSkew", long.class);
+
+ /**
* <p>Quality of lens shading correction applied
* to the image data.</p>
* <p>When set to OFF mode, no lens shading correction will be applied by the
@@ -2188,7 +2273,7 @@
* lens shading map data in android.statistics.lensShadingMap, with size specified
* by android.lens.info.shadingMapSize; the returned shading map data will be the one
* applied by the camera device for this capture request.</p>
- * <p>The shading map data may depend on the AE and AWB statistics, therefore the reliability
+ * <p>The shading map data may depend on the auto-exposure (AE) and AWB statistics, therefore the reliability
* of the map data may be affected by the AE and AWB algorithms. When AE and AWB are in
* AUTO modes({@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF and {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} <code>!=</code> OFF),
* to get best results, it is recommended that the applications wait for the AE and AWB to
@@ -2205,8 +2290,8 @@
new Key<Integer>("android.shading.mode", int.class);
/**
- * <p>State of the face detector
- * unit</p>
+ * <p>Control for the face detector
+ * unit.</p>
* <p>Whether face detection is enabled, and whether it
* should output just the basic fields or the full set of
* fields. Value must be one of the
@@ -2221,9 +2306,13 @@
new Key<Integer>("android.statistics.faceDetectMode", int.class);
/**
- * <p>List of unique IDs for detected
- * faces</p>
- * <p>Only available if faceDetectMode == FULL</p>
+ * <p>List of unique IDs for detected faces.</p>
+ * <p>Each detected face is given a unique ID that is valid for as long as the face is visible
+ * to the camera device. A face that leaves the field of view and later returns may be
+ * assigned a new ID.</p>
+ * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} == FULL</p>
+ *
+ * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
* @hide
*/
public static final Key<int[]> STATISTICS_FACE_IDS =
@@ -2231,8 +2320,13 @@
/**
* <p>List of landmarks for detected
- * faces</p>
- * <p>Only available if faceDetectMode == FULL</p>
+ * faces.</p>
+ * <p>The coordinate system is that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
+ * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} == FULL</p>
+ *
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
* @hide
*/
public static final Key<int[]> STATISTICS_FACE_LANDMARKS =
@@ -2240,8 +2334,13 @@
/**
* <p>List of the bounding rectangles for detected
- * faces</p>
- * <p>Only available if faceDetectMode != OFF</p>
+ * faces.</p>
+ * <p>The coordinate system is that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
+ * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} != OFF</p>
+ *
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
* @hide
*/
public static final Key<android.graphics.Rect[]> STATISTICS_FACE_RECTANGLES =
@@ -2250,8 +2349,9 @@
/**
* <p>List of the face confidence scores for
* detected faces</p>
- * <p>Only available if faceDetectMode != OFF. The value should be
- * meaningful (for example, setting 100 at all times is illegal).</p>
+ * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} != OFF.</p>
+ *
+ * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
* @hide
*/
public static final Key<byte[]> STATISTICS_FACE_SCORES =
@@ -2370,7 +2470,7 @@
* applied to that frame.</p>
* <p>The 4 channel gains are defined in Bayer domain,
* see {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} for details.</p>
- * <p>This value should always be calculated by the AWB block,
+ * <p>This value should always be calculated by the auto-white balance (AWB) block,
* regardless of the android.control.* current values.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
@@ -2396,7 +2496,7 @@
* that frame.</p>
* <p>These estimates must be provided for all frames, even if
* capture settings and color transforms are set by the application.</p>
- * <p>This value should always be calculated by the AWB block,
+ * <p>This value should always be calculated by the auto-white balance (AWB) block,
* regardless of the android.control.* current values.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* @deprecated
@@ -2415,12 +2515,13 @@
* The camera device uses this entry to tell the application what the scene
* illuminant frequency is.</p>
* <p>When manual exposure control is enabled
- * (<code>{@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} == OFF</code> or <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == OFF</code>),
- * the {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} doesn't do the antibanding, and the
- * application can ensure it selects exposure times that do not cause banding
- * issues by looking into this metadata field. See {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode}
- * for more details.</p>
- * <p>Report NONE if there doesn't appear to be flickering illumination.</p>
+ * (<code>{@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} == OFF</code> or <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} ==
+ * OFF</code>), the {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} doesn't perform
+ * antibanding, and the application can ensure it selects
+ * exposure times that do not cause banding issues by looking
+ * into this metadata field. See
+ * {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} for more details.</p>
+ * <p>Reports NONE if there doesn't appear to be flickering illumination.</p>
*
* @see CaptureRequest#CONTROL_AE_ANTIBANDING_MODE
* @see CaptureRequest#CONTROL_AE_MODE
@@ -2435,7 +2536,7 @@
/**
* <p>Operating mode for hotpixel map generation.</p>
* <p>If set to ON, a hotpixel map is returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.
- * If set to OFF, no hotpixel map should be returned.</p>
+ * If set to OFF, no hotpixel map will be returned.</p>
* <p>This must be set to a valid mode from {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES android.statistics.info.availableHotPixelMapModes}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
@@ -2463,7 +2564,7 @@
* <p>Whether the camera device will output the lens
* shading map in output result metadata.</p>
* <p>When set to ON,
- * android.statistics.lensShadingMap must be provided in
+ * android.statistics.lensShadingMap will be provided in
* the output result metadata.</p>
* @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
* @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index c3e042e..f829f5e 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -118,9 +118,11 @@
if (configureSuccess) {
mStateListener.onConfigured(this);
+ if (VERBOSE) Log.v(TAG, "ctor - Created session successfully");
} else {
mStateListener.onConfigureFailed(this);
mClosed = true; // do not fire any other callbacks, do not allow any other work
+ Log.e(TAG, "Failed to create capture session; configuration failed");
}
}
@@ -132,6 +134,10 @@
@Override
public synchronized int capture(CaptureRequest request, CaptureListener listener,
Handler handler) throws CameraAccessException {
+ if (request == null) {
+ throw new IllegalArgumentException("request must not be null");
+ }
+
checkNotClosed();
checkLegalToCapture();
@@ -139,7 +145,7 @@
if (VERBOSE) {
Log.v(TAG, "capture - request " + request + ", listener " + listener + " handler" +
- "" + handler);
+ " " + handler);
}
return addPendingSequence(mDeviceImpl.capture(request,
@@ -149,6 +155,12 @@
@Override
public synchronized int captureBurst(List<CaptureRequest> requests, CaptureListener listener,
Handler handler) throws CameraAccessException {
+ if (requests == null) {
+ throw new IllegalArgumentException("requests must not be null");
+ } else if (requests.isEmpty()) {
+ throw new IllegalArgumentException("requests must have at least one element");
+ }
+
checkNotClosed();
checkLegalToCapture();
@@ -167,11 +179,20 @@
@Override
public synchronized int setRepeatingRequest(CaptureRequest request, CaptureListener listener,
Handler handler) throws CameraAccessException {
+ if (request == null) {
+ throw new IllegalArgumentException("request must not be null");
+ }
+
checkNotClosed();
checkLegalToCapture();
handler = checkHandler(handler);
+ if (VERBOSE) {
+ Log.v(TAG, "setRepeatingRequest - request " + request + ", listener " + listener +
+ " handler" + " " + handler);
+ }
+
return addPendingSequence(mDeviceImpl.setRepeatingRequest(request,
createCaptureListenerProxy(handler, listener), mDeviceHandler));
}
@@ -179,6 +200,12 @@
@Override
public synchronized int setRepeatingBurst(List<CaptureRequest> requests,
CaptureListener listener, Handler handler) throws CameraAccessException {
+ if (requests == null) {
+ throw new IllegalArgumentException("requests must not be null");
+ } else if (requests.isEmpty()) {
+ throw new IllegalArgumentException("requests must have at least one element");
+ }
+
checkNotClosed();
checkLegalToCapture();
@@ -249,8 +276,11 @@
* but this would introduce nondeterministic behavior.
*/
+ if (VERBOSE) Log.v(TAG, "replaceSessionClose");
+
// #close was already called explicitly, keep going the slow route
if (mClosed) {
+ if (VERBOSE) Log.v(TAG, "replaceSessionClose - close was already called");
return;
}
@@ -260,21 +290,39 @@
@Override
public synchronized void close() {
+
if (mClosed) {
+ if (VERBOSE) Log.v(TAG, "close - reentering");
return;
}
+ if (VERBOSE) Log.v(TAG, "close - first time");
+
mClosed = true;
/*
* Flush out any repeating request. Since camera is closed, no new requests
* can be queued, and eventually the entire request queue will be drained.
*
- * Once this is done, wait for camera to idle, then unconfigure the camera.
- * Once that's done, fire #onClosed.
+ * If the camera device was already closed, short circuit and do nothing; since
+ * no more internal device callbacks will fire anyway.
+ *
+ * Otherwise, once stopRepeating is done, wait for camera to idle, then unconfigure the
+ * camera. Once that's done, fire #onClosed.
*/
try {
mDeviceImpl.stopRepeating();
+ } catch (IllegalStateException e) {
+ // OK: Camera device may already be closed, nothing else to do
+ Log.w(TAG, "The camera device was already closed: ", e);
+
+ // TODO: Fire onClosed anytime we get the device onClosed or the ISE?
+ // or just suppress the ISE only and rely onClosed.
+ // Also skip any of the draining work if this is already closed.
+
+ // Short-circuit; queue listener immediately and return
+ mStateListener.onClosed(this);
+ return;
} catch (CameraAccessException e) {
// OK: close does not throw checked exceptions.
Log.e(TAG, "Exception while stopping repeating: ", e);
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index d4adae1..d9f3af4 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -257,6 +257,7 @@
synchronized (mLock) {
mInError = true;
mDeviceHandler.post(new Runnable() {
+ @Override
public void run() {
if (isError) {
mDeviceListener.onError(CameraDeviceImpl.this, code);
@@ -360,6 +361,9 @@
} catch (CameraAccessException e) {
configureSuccess = false;
pendingException = e;
+ if (DEBUG) {
+ Log.v(TAG, "createCaptureSession - failed with exception ", e);
+ }
}
// Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
diff --git a/core/java/android/hardware/camera2/package.html b/core/java/android/hardware/camera2/package.html
index 9f6c2a9..ef0d7bd 100644
--- a/core/java/android/hardware/camera2/package.html
+++ b/core/java/android/hardware/camera2/package.html
@@ -34,49 +34,71 @@
CameraDevices} provide a set of static property information that
describes the hardware device and the available settings and output
parameters for the device. This information is provided through the
-{@link android.hardware.camera2.CameraCharacteristics} object.</p>
+{@link android.hardware.camera2.CameraCharacteristics} object, and is
+available through {@link
+android.hardware.camera2.CameraManager#getCameraCharacteristics}</p>
<p>To capture or stream images from a camera device, the application
-must first configure a set of output Surfaces for use with the camera
-device, with {@link
-android.hardware.camera2.CameraDevice#configureOutputs}. Each
-Surface has to be pre-configured with an appropriate size and format
-(if applicable) to match the sizes and formats available from the
-camera device. A target Surface can be obtained from a variety of
-classes, including {@link android.view.SurfaceView}, {@link
-android.graphics.SurfaceTexture} via {@link
-android.view.Surface#Surface(SurfaceTexture), {@link
-android.media.MediaCodec}, and {@link android.media.ImageReader}.
+must first create a {@link
+android.hardware.camera2.CameraCaptureSession camera capture session}
+with a set of output Surfaces for use with the camera device, with
+{@link
+android.hardware.camera2.CameraDevice#createCaptureSession}. Each
+Surface has to be pre-configured with an {@link
+android.hardware.camera2.params.StreamConfigurationMap appropriate
+size and format} (if applicable) to match the sizes and formats
+available from the camera device. A target Surface can be obtained
+from a variety of classes, including {@link android.view.SurfaceView},
+{@link android.graphics.SurfaceTexture} via
+{@link android.view.Surface#Surface(SurfaceTexture)},
+{@link android.media.MediaCodec}, {@link android.media.MediaRecorder},
+{@link android.renderscript.Allocation}, and {@link android.media.ImageReader}.
</p>
+<p>Generally, camera preview images are sent to {@link
+android.view.SurfaceView} or {@link android.view.TextureView} (via its
+{@link android.graphics.SurfaceTexture}). Capture of JPEG images or
+RAW buffers for {@link android.hardware.camera2.DngCreator} can be done
+with {@link android.media.ImageReader} with the
+{android.graphics.ImageFormat#JPEG} and
+{android.graphics.ImageFormat#RAW_SENSOR} formats. Application-driven
+processing of camera data in RenderScript, OpenGL ES, or directly in
+managed or native code is best done through {@link
+android.renderscript.Allocation} with a YUV {@link
+android.renderscript.Type}, {@link android.graphics.SurfaceTexture},
+and {@link android.media.ImageReader} with a
+{android.graphics.ImageFormat#YUV_420_888} format, respectively.</p>
+
<p>The application then needs to construct a {@link
android.hardware.camera2.CaptureRequest}, which defines all the
capture parameters needed by a camera device to capture a single
image. The request also lists which of the configured output Surfaces
should be used as targets for this capture. The CameraDevice has a
{@link android.hardware.camera2.CameraDevice#createCaptureRequest
-convenience factory method} for creating a request for a given use
-case which is optimized for the Android device the application is
-running on.</p>
+factory method} for creating a {@link
+android.hardware.camera2.CaptureRequest.Builder request builder} for a
+given use case, which is optimized for the Android device the
+application is running on.</p>
-<p>Once the request has been set up, it can be handed to the
-CameraDevice either for a one-shot {@link
-android.hardware.camera2.CameraDevice#capture} or for an endlessly
-{@link android.hardware.camera2.CameraDevice#setRepeatingRequest
-repeating} use. Both methods also accept a list of requests to use as
-a burst capture / repeating burst. Repeating requests have a lower
-priority than captures, so a request submitted
+<p>Once the request has been set up, it can be handed to the active
+capture session either for a one-shot {@link
+android.hardware.camera2.CameraCaptureSession#capture capture} or for
+an endlessly {@link
+android.hardware.camera2.CameraCaptureSession#setRepeatingRequest
+repeating} use. Both methods also have a variant that accepts a list
+of requests to use as a burst capture / repeating burst. Repeating
+requests have a lower priority than captures, so a request submitted
through <code>capture()</code> while there's a repeating request
-configured will be captured as soon as the current repeat (burst)
-capture completes.</p>
+configured will be captured before any new instances of the currently
+repeating (burst) capture will begin capture.</p>
<p>After processing a request, the camera device will produce a {@link
-android.hardware.camera2.CaptureResult} object, which contains
+android.hardware.camera2.TotalCaptureResult} object, which contains
information about the state of the camera device at time of capture,
and the final settings used. These may vary somewhat from the request,
if rounding or resolving contradictory parameters was necessary. The
camera device will also send a frame of image data into each of the
-output streams included in the request. These are produced
+output {@code Surfaces} included in the request. These are produced
asynchronously relative to the output CaptureResult, sometimes
substantially later.</p>
diff --git a/core/java/android/hardware/camera2/params/StreamConfiguration.java b/core/java/android/hardware/camera2/params/StreamConfiguration.java
index 1c6b6e9..a6fc10f 100644
--- a/core/java/android/hardware/camera2/params/StreamConfiguration.java
+++ b/core/java/android/hardware/camera2/params/StreamConfiguration.java
@@ -28,8 +28,9 @@
/**
* Immutable class to store the available stream
- * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to be used
- * when configuring streams with {@link CameraDevice#configureOutputs}.
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to set up
+ * {@link android.view.Surface Surfaces} for creating a {@link CameraCaptureSession capture session}
+ * with {@link CameraDevice#createCaptureSession}.
* <!-- TODO: link to input stream configuration -->
*
* <p>This is the authoritative list for all input/output formats (and sizes respectively
@@ -124,7 +125,7 @@
*
* @return {@code true} if output configuration, {@code false} otherwise
*
- * @see CameraDevice#configureOutputs
+ * @see CameraDevice#createCaptureSession
*/
public boolean isOutput() {
return !mInput;
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 4cd6d15..3036425 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -34,8 +34,10 @@
/**
* Immutable class to store the available stream
- * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP configurations} to be used
- * when configuring streams with {@link CameraDevice#configureOutputs}.
+ * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP configurations} to set up
+ * {@link android.view.Surface Surfaces} for creating a
+ * {@link android.hardware.camera2.CameraCaptureSession capture session} with
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession}.
* <!-- TODO: link to input stream configuration -->
*
* <p>This is the authoritative list for all <!-- input/ -->output formats (and sizes respectively
@@ -56,7 +58,7 @@
* }</code></pre>
*
* @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
- * @see CameraDevice#configureOutputs
+ * @see CameraDevice#createCaptureSession
*/
public final class StreamConfigurationMap {
@@ -155,8 +157,8 @@
}
/**
- * Determine whether or not output streams can be
- * {@link CameraDevice#configureOutputs configured} with a particular user-defined format.
+ * Determine whether or not output surfaces with a particular user-defined format can be passed
+ * {@link CameraDevice#createCaptureSession createCaptureSession}.
*
* <p>This method determines that the output {@code format} is supported by the camera device;
* each output {@code surface} target may or may not itself support that {@code format}.
@@ -168,7 +170,7 @@
* @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
* @return
* {@code true} iff using a {@code surface} with this {@code format} will be
- * supported with {@link CameraDevice#configureOutputs}
+ * supported with {@link CameraDevice#createCaptureSession}
*
* @throws IllegalArgumentException
* if the image format was not a defined named constant
@@ -176,7 +178,7 @@
*
* @see ImageFormat
* @see PixelFormat
- * @see CameraDevice#configureOutputs
+ * @see CameraDevice#createCaptureSession
*/
public boolean isOutputSupportedFor(int format) {
checkArgumentFormat(format);
@@ -210,7 +212,7 @@
*
* <p>Generally speaking this means that creating a {@link Surface} from that class <i>may</i>
* provide a producer endpoint that is suitable to be used with
- * {@link CameraDevice#configureOutputs}.</p>
+ * {@link CameraDevice#createCaptureSession}.</p>
*
* <p>Since not all of the above classes support output of all format and size combinations,
* the particular combination should be queried with {@link #isOutputSupportedFor(Surface)}.</p>
@@ -220,7 +222,7 @@
*
* @throws NullPointerException if {@code klass} was {@code null}
*
- * @see CameraDevice#configureOutputs
+ * @see CameraDevice#createCaptureSession
* @see #isOutputSupportedFor(Surface)
*/
public static <T> boolean isOutputSupportedFor(Class<T> klass) {
@@ -244,8 +246,8 @@
}
/**
- * Determine whether or not the {@code surface} in its current state is suitable to be
- * {@link CameraDevice#configureOutputs configured} as an output.
+ * Determine whether or not the {@code surface} in its current state is suitable to be included
+ * in a {@link CameraDevice#createCaptureSession capture session} as an output.
*
* <p>Not all surfaces are usable with the {@link CameraDevice}, and not all configurations
* of that {@code surface} are compatible. Some classes that provide the {@code surface} are
@@ -269,7 +271,7 @@
*
* @throws NullPointerException if {@code surface} was {@code null}
*
- * @see CameraDevice#configureOutputs
+ * @see CameraDevice#createCaptureSession
* @see #isOutputSupportedFor(Class)
*/
public boolean isOutputSupportedFor(Surface surface) {
diff --git a/core/java/android/hardware/camera2/utils/TaskDrainer.java b/core/java/android/hardware/camera2/utils/TaskDrainer.java
index 3cba9a1..dc09f62 100644
--- a/core/java/android/hardware/camera2/utils/TaskDrainer.java
+++ b/core/java/android/hardware/camera2/utils/TaskDrainer.java
@@ -52,7 +52,7 @@
}
private static final String TAG = "TaskDrainer";
- private static final boolean VERBOSE = false;
+ private final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
private final Handler mHandler;
private final DrainListener mListener;
diff --git a/core/java/android/hardware/hdmi/HdmiCec.java b/core/java/android/hardware/hdmi/HdmiCec.java
index 723eda1..8ad9463 100644
--- a/core/java/android/hardware/hdmi/HdmiCec.java
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -16,9 +16,14 @@
package android.hardware.hdmi;
+import android.annotation.SystemApi;
+
/**
* Defines constants and utility methods related to HDMI-CEC protocol.
+ *
+ * @hide
*/
+@SystemApi
public final class HdmiCec {
/** TV device type. */
diff --git a/core/java/android/hardware/hdmi/HdmiCecClient.java b/core/java/android/hardware/hdmi/HdmiCecClient.java
deleted file mode 100644
index dcb3624..0000000
--- a/core/java/android/hardware/hdmi/HdmiCecClient.java
+++ /dev/null
@@ -1,119 +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.hardware.hdmi;
-
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import android.util.Log;
-
-/**
- * HdmiCecClient is used to control HDMI-CEC logical device instance in the system.
- * It is connected to actual hardware part via HdmiCecService. It provides with methods
- * to send CEC messages to other device on the bus, and listener that allows to receive
- * incoming messages to the device.
- */
-public final class HdmiCecClient {
- private static final String TAG = "HdmiCecClient";
-
- private final IHdmiCecService mService;
- private final IBinder mBinder;
-
- /**
- * Listener used by the client to get the incoming messages.
- */
- public static abstract class Listener {
- /**
- * Called when CEC message arrives. Override this method to receive the incoming
- * CEC messages from other device on the bus.
- *
- * @param message {@link HdmiCecMessage} object
- */
- public void onMessageReceived(HdmiCecMessage message) { }
-
- /**
- * Called when hotplug event occurs. Override this method to receive the events.
- *
- * @param connected true if the cable is connected; otherwise false.
- */
- public void onCableStatusChanged(boolean connected) { }
- }
-
- // Private constructor.
- private HdmiCecClient(IHdmiCecService service, IBinder b) {
- mService = service;
- mBinder = b;
- }
-
- // Factory method for HdmiCecClient.
- // Declared package-private. Accessed by HdmiCecManager only.
- static HdmiCecClient create(IHdmiCecService service, IBinder b) {
- return new HdmiCecClient(service, b);
- }
-
- /**
- * Send <Active Source> message.
- */
- public void sendActiveSource() {
- Log.w(TAG, "In transition to HdmiControlManager. Will not work.");
- }
-
- /**
- * Send <Inactive Source> message.
- */
- public void sendInactiveSource() {
- Log.w(TAG, "In transition to HdmiControlManager. Will not work.");
- }
-
- /**
- * Send <Text View On> message.
- */
- public void sendTextViewOn() {
- Log.w(TAG, "In transition to HdmiControlManager. Will not work.");
- }
-
- /**
- * Send <Image View On> message.
- */
- public void sendImageViewOn() {
- Log.w(TAG, "In transition to HdmiControlManager. Will not work.");
- }
-
- /**
- * Send <Give Device Power Status> message.
- *
- * @param address logical address of the device to send the message to, such as
- * {@link HdmiCec#ADDR_TV}.
- */
- public void sendGiveDevicePowerStatus(int address) {
- Log.w(TAG, "In transition to HdmiControlManager. Will not work.");
- }
-
- /**
- * Returns true if the TV or attached display is powered on.
- * <p>
- * The result of this method is only meaningful on playback devices (where the device
- * type is {@link HdmiCec#DEVICE_PLAYBACK}).
- * </p>
- *
- * @return true if TV is on; otherwise false.
- */
- public boolean isTvOn() {
- Log.w(TAG, "In transition to HdmiControlManager. Will not work.");
- return true;
- }
-}
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.aidl
similarity index 89%
copy from core/java/android/app/task/Task.aidl
copy to core/java/android/hardware/hdmi/HdmiCecDeviceInfo.aidl
index 1f25439..1615910 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.aidl
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-package android.app.task;
+package android.hardware.hdmi;
-parcelable Task;
-
\ No newline at end of file
+parcelable HdmiCecDeviceInfo;
diff --git a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
index 9698445..fbfcca0 100644
--- a/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiCecDeviceInfo.java
@@ -16,6 +16,7 @@
package android.hardware.hdmi;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -23,7 +24,10 @@
* A class to encapsulate device information for HDMI-CEC. This container
* include basic information such as logical address, physical address and
* device type, and additional information like vendor id and osd name.
+ *
+ * @hide
*/
+@SystemApi
public final class HdmiCecDeviceInfo implements Parcelable {
// Logical address, phsical address, device type, vendor id and display name
// are immutable value.
diff --git a/core/java/android/hardware/hdmi/HdmiCecManager.java b/core/java/android/hardware/hdmi/HdmiCecManager.java
deleted file mode 100644
index 03c46d8..0000000
--- a/core/java/android/hardware/hdmi/HdmiCecManager.java
+++ /dev/null
@@ -1,68 +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.hardware.hdmi;
-
-import android.os.IBinder;
-import android.os.RemoteException;
-
-/**
- * The HdmiCecManager class is used to provide an HdmiCecClient instance,
- * get various information on HDMI ports configuration. It is connected to actual hardware
- * via HdmiCecService.
- */
-public final class HdmiCecManager {
- private final IHdmiCecService mService;
-
- /**
- * @hide - hide this constructor because it has a parameter of type IHdmiCecService,
- * which is a system private class. The right way to create an instance of this class
- * is using the factory Context.getSystemService.
- */
- public HdmiCecManager(IHdmiCecService service) {
- mService = service;
- }
-
- /**
- * Provide the HdmiCecClient instance of the given type. It also registers the listener
- * for client to get the events coming to the device.
- *
- * @param type type of the HDMI-CEC logical device
- * @param listener listener to be called
- * @return {@link HdmiCecClient} instance. {@code null} on failure.
- */
- public HdmiCecClient getClient(int type, HdmiCecClient.Listener listener) {
- return HdmiCecClient.create(mService, null);
- }
-
- private IHdmiCecListener getListenerWrapper(final HdmiCecClient.Listener listener) {
- // TODO: The message/events are not yet forwarded to client since it is not clearly
- // defined as to how/who to handle them. Revisit it once the decision is
- // made on what messages will have to reach the clients, what will be
- // handled by service/manager.
- return new IHdmiCecListener.Stub() {
- @Override
- public void onMessageReceived(HdmiCecMessage message) {
- // Do nothing.
- }
-
- @Override
- public void onCableStatusChanged(boolean connected) {
- // Do nothing.
- }
- };
- }
-}
diff --git a/core/java/android/hardware/hdmi/HdmiCecMessage.java b/core/java/android/hardware/hdmi/HdmiCecMessage.java
index 62fa279..ac16ad8 100644
--- a/core/java/android/hardware/hdmi/HdmiCecMessage.java
+++ b/core/java/android/hardware/hdmi/HdmiCecMessage.java
@@ -16,6 +16,7 @@
package android.hardware.hdmi;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -27,7 +28,10 @@
* A class to encapsulate HDMI-CEC message used for the devices connected via
* HDMI cable to communicate with one another. A message is defined by its
* source and destination address, command (or opcode), and optional parameters.
+ *
+ * @hide
*/
+@SystemApi
public final class HdmiCecMessage implements Parcelable {
public static final byte[] EMPTY_PARAM = EmptyArray.BYTE;
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 5b6e862..f15fa00 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -17,6 +17,7 @@
package android.hardware.hdmi;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.RemoteException;
/**
@@ -28,7 +29,10 @@
* {@link HdmiTvClient} object if the system is configured to host one. Android system
* can host more than one logical CEC devices. If multiple types are configured they
* all work as if they were independent logical devices running in the system.
+ *
+ * @hide
*/
+@SystemApi
public final class HdmiControlManager {
@Nullable private final IHdmiControlService mService;
diff --git a/core/java/android/hardware/hdmi/HdmiHotplugEvent.java b/core/java/android/hardware/hdmi/HdmiHotplugEvent.java
index 1462f83..7be4bc5 100644
--- a/core/java/android/hardware/hdmi/HdmiHotplugEvent.java
+++ b/core/java/android/hardware/hdmi/HdmiHotplugEvent.java
@@ -16,12 +16,16 @@
package android.hardware.hdmi;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
/**
* A class that describes the HDMI port hotplug event.
+ *
+ * @hide
*/
+@SystemApi
public final class HdmiHotplugEvent implements Parcelable {
private final int mPort;
diff --git a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
index f0bd237..2e49a38 100644
--- a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
+++ b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
@@ -16,6 +16,7 @@
package android.hardware.hdmi;
+import android.annotation.SystemApi;
import android.os.RemoteException;
import android.util.Log;
@@ -25,7 +26,10 @@
* in the Android system which acts as a playback device such as set-top box.
* It provides with methods that control, get information from TV/Display device
* connected through HDMI bus.
+ *
+ * @hide
*/
+@SystemApi
public final class HdmiPlaybackClient {
private static final String TAG = "HdmiPlaybackClient";
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/hardware/hdmi/HdmiPortInfo.aidl
similarity index 90%
copy from core/java/android/app/task/Task.aidl
copy to core/java/android/hardware/hdmi/HdmiPortInfo.aidl
index 1f25439..157b5b3 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/core/java/android/hardware/hdmi/HdmiPortInfo.aidl
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-package android.app.task;
+package android.hardware.hdmi;
-parcelable Task;
-
\ No newline at end of file
+parcelable HdmiPortInfo;
diff --git a/core/java/android/hardware/hdmi/HdmiPortInfo.java b/core/java/android/hardware/hdmi/HdmiPortInfo.java
new file mode 100644
index 0000000..7b25f8a
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiPortInfo.java
@@ -0,0 +1,164 @@
+/*
+ * 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.hardware.hdmi;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class to encapsulate HDMI port information. Contains the capability of the ports such as
+ * HDMI-CEC, MHL, ARC(Audio Return Channel), and physical address assigned to each port.
+ *
+ * @hide
+ */
+@SystemApi
+public final class HdmiPortInfo implements Parcelable {
+ /** HDMI port type: Input */
+ public static final int PORT_INPUT = 0;
+
+ /** HDMI port type: Output */
+ public static final int PORT_OUTPUT = 1;
+
+ private final int mId;
+ private final int mType;
+ private final int mAddress;
+ private final boolean mCecSupported;
+ private final boolean mArcSupported;
+ private final boolean mMhlSupported;
+
+ /**
+ * Constructor.
+ *
+ * @param id identifier assigned to each port. 1 for HDMI port 1
+ * @param type HDMI port input/output type
+ * @param address physical address of the port
+ * @param cec {@code true} if HDMI-CEC is supported on the port
+ * @param mhl {@code true} if MHL is supported on the port
+ * @param arc {@code true} if audio return channel is supported on the port
+ */
+ public HdmiPortInfo(int id, int type, int address, boolean cec, boolean mhl, boolean arc) {
+ mId = id;
+ mType = type;
+ mAddress = address;
+ mCecSupported = cec;
+ mArcSupported = arc;
+ mMhlSupported = mhl;
+ }
+
+ /**
+ * Returns the port id.
+ *
+ * @return port id
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Returns the port type.
+ *
+ * @return port type
+ */
+ public int getType() {
+ return mType;
+ }
+
+ /**
+ * Returns the port address.
+ *
+ * @return port address
+ */
+ public int getAddress() {
+ return mAddress;
+ }
+
+ /**
+ * Returns {@code true} if the port supports HDMI-CEC signaling.
+ *
+ * @return {@code true} if the port supports HDMI-CEC signaling.
+ */
+ public boolean isCecSupported() {
+ return mCecSupported;
+ }
+
+ /**
+ * Returns {@code true} if the port supports MHL signaling.
+ *
+ * @return {@code true} if the port supports MHL signaling.
+ */
+ public boolean isMhlSupported() {
+ return mMhlSupported;
+ }
+
+ /**
+ * Returns {@code true} if the port supports audio return channel.
+ *
+ * @return {@code true} if the port supports audio return channel
+ */
+ public boolean isArcSupported() {
+ return mArcSupported;
+ }
+
+ /**
+ * Describe the kinds of special objects contained in this Parcelable's
+ * marshalled representation.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+
+ /**
+ * A helper class to deserialize {@link HdmiPortInfo} for a parcel.
+ */
+ public static final Parcelable.Creator<HdmiPortInfo> CREATOR =
+ new Parcelable.Creator<HdmiPortInfo>() {
+ @Override
+ public HdmiPortInfo createFromParcel(Parcel source) {
+ int id = source.readInt();
+ int type = source.readInt();
+ int address = source.readInt();
+ boolean cec = (source.readInt() == 1);
+ boolean arc = (source.readInt() == 1);
+ boolean mhl = (source.readInt() == 1);
+ return new HdmiPortInfo(id, type, address, cec, arc, mhl);
+ }
+
+ @Override
+ public HdmiPortInfo[] newArray(int size) {
+ return new HdmiPortInfo[size];
+ }
+ };
+
+ /**
+ * Serialize this object into a {@link Parcel}.
+ *
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ * May be 0 or {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mId);
+ dest.writeInt(mType);
+ dest.writeInt(mAddress);
+ dest.writeInt(mCecSupported ? 1 : 0);
+ dest.writeInt(mArcSupported ? 1 : 0);
+ dest.writeInt(mMhlSupported ? 1 : 0);
+ }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index 73c72472..85af3d1 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -15,11 +15,18 @@
*/
package android.hardware.hdmi;
+import android.annotation.SystemApi;
+import android.os.RemoteException;
+import android.util.Log;
+
/**
* HdmiTvClient represents HDMI-CEC logical device of type TV in the Android system
* which acts as TV/Display. It provides with methods that manage, interact with other
* devices on the CEC bus.
+ *
+ * @hide
*/
+@SystemApi
public final class HdmiTvClient {
private static final String TAG = "HdmiTvClient";
@@ -28,4 +35,46 @@
HdmiTvClient(IHdmiControlService service) {
mService = service;
}
+
+ // Factory method for HdmiTvClient.
+ // Declared package-private. Accessed by HdmiControlManager only.
+ static HdmiTvClient create(IHdmiControlService service) {
+ return new HdmiTvClient(service);
+ }
+
+ /**
+ * Callback interface used to get the result of {@link #deviceSelect}.
+ */
+ public interface SelectCallback {
+ /**
+ * Called when the operation is finished.
+ *
+ * @param result the result value of {@link #deviceSelect}
+ */
+ void onComplete(int result);
+ }
+
+ /**
+ * Select a CEC logical device to be a new active source.
+ *
+ * @param logicalAddress
+ * @param callback
+ */
+ public void deviceSelect(int logicalAddress, SelectCallback callback) {
+ // TODO: Replace SelectCallback with PartialResult.
+ try {
+ mService.deviceSelect(logicalAddress, getCallbackWrapper(callback));
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to select device: ", e);
+ }
+ }
+
+ private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) {
+ return new IHdmiControlCallback.Stub() {
+ @Override
+ public void onComplete(int result) {
+ callback.onComplete(result);
+ }
+ };
+ }
}
diff --git a/core/java/android/hardware/hdmi/IHdmiCecService.aidl b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
deleted file mode 100644
index ecdd345..0000000
--- a/core/java/android/hardware/hdmi/IHdmiCecService.aidl
+++ /dev/null
@@ -1,40 +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.hardware.hdmi;
-
-import android.hardware.hdmi.HdmiCecMessage;
-import android.hardware.hdmi.IHdmiCecListener;
-import android.os.IBinder;
-
-/**
- * Binder interface that components running in the appplication process
- * will use to enable HDMI-CEC protocol exchange with other devices.
- *
- * @hide
- */
-interface IHdmiCecService {
- IBinder allocateLogicalDevice(int type, IHdmiCecListener listener);
- void removeServiceListener(IBinder b, IHdmiCecListener listener);
- void sendActiveSource(IBinder b);
- void sendInactiveSource(IBinder b);
- void sendImageViewOn(IBinder b);
- void sendTextViewOn(IBinder b);
- void sendGiveDevicePowerStatus(IBinder b, int address);
- boolean isTvOn(IBinder b);
- void sendMessage(IBinder b, in HdmiCecMessage message);
-}
-
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 8da38e1..559a469 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -16,10 +16,14 @@
package android.hardware.hdmi;
-import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.hdmi.IHdmiDeviceEventListener;
import android.hardware.hdmi.IHdmiHotplugEventListener;
+import java.util.List;
+
/**
* Binder interface that clients running in the application process
* will use to perform HDMI-CEC features by communicating with other devices
@@ -33,4 +37,9 @@
void queryDisplayStatus(IHdmiControlCallback callback);
void addHotplugEventListener(IHdmiHotplugEventListener listener);
void removeHotplugEventListener(IHdmiHotplugEventListener listener);
+ void addDeviceEventListener(IHdmiDeviceEventListener listener);
+ void deviceSelect(int logicalAddress, IHdmiControlCallback callback);
+ void portSelect(int portId, IHdmiControlCallback callback);
+ void sendKeyEvent(int keyCode, boolean isPressed);
+ List<HdmiPortInfo> getPortInfo();
}
diff --git a/core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl b/core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl
new file mode 100644
index 0000000..c4e5989
--- /dev/null
+++ b/core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.hardware.hdmi;
+
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+
+/**
+ * Callback interface definition for HDMI client to get informed of
+ * the CEC logical device status change event.
+ *
+ * @hide
+ */
+oneway interface IHdmiDeviceEventListener {
+
+ /**
+ * @param deviceInfo {@link HdmiCecDeviceInfo} of the logical device whose
+ * status has changed
+ * @param activated true if the device gets activated
+ */
+ void onStatusChanged(in HdmiCecDeviceInfo deviceInfo, in boolean activated);
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index b96f166..ba31243 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -22,6 +22,7 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.net.NetworkUtils;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
import android.os.Handler;
@@ -428,6 +429,11 @@
*/
public final static int INVALID_NET_ID = 0;
+ /**
+ * @hide
+ */
+ public final static int REQUEST_ID_UNSET = 0;
+
private final IConnectivityManager mService;
private final String mPackageName;
@@ -862,10 +868,10 @@
return -1;
}
- NetworkRequest request = removeRequestForFeature(netCap);
- if (request != null) {
+ NetworkCallback networkCallback = removeRequestForFeature(netCap);
+ if (networkCallback != null) {
Log.d(TAG, "stopUsingNetworkFeature for " + networkType + ", " + feature);
- releaseNetworkRequest(request);
+ unregisterNetworkCallback(networkCallback);
}
return 1;
}
@@ -882,8 +888,8 @@
* @hide
*/
public static void maybeMarkCapabilitiesRestricted(NetworkCapabilities nc) {
- for (Integer capability : nc.getNetworkCapabilities()) {
- switch (capability.intValue()) {
+ for (int capability : nc.getCapabilities()) {
+ switch (capability) {
case NetworkCapabilities.NET_CAPABILITY_CBS:
case NetworkCapabilities.NET_CAPABILITY_DUN:
case NetworkCapabilities.NET_CAPABILITY_EIMS:
@@ -892,6 +898,7 @@
case NetworkCapabilities.NET_CAPABILITY_IMS:
case NetworkCapabilities.NET_CAPABILITY_RCS:
case NetworkCapabilities.NET_CAPABILITY_XCAP:
+ case NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED: //there by default
continue;
default:
// At least one capability usually provided by unrestricted
@@ -901,7 +908,7 @@
}
// All the capabilities are typically provided by restricted networks.
// Conclude that this network is restricted.
- nc.removeNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
}
private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) {
@@ -925,15 +932,14 @@
return null;
}
NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
- netCap.addNetworkCapability(cap);
+ netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addCapability(cap);
maybeMarkCapabilitiesRestricted(netCap);
return netCap;
} else if (networkType == TYPE_WIFI) {
if ("p2p".equals(feature)) {
NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
+ netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
maybeMarkCapabilitiesRestricted(netCap);
return netCap;
}
@@ -976,18 +982,18 @@
int expireSequenceNumber;
Network currentNetwork;
int delay = -1;
- NetworkCallbackListener networkCallbackListener = new NetworkCallbackListener() {
+ NetworkCallback networkCallback = new NetworkCallback() {
@Override
- public void onAvailable(NetworkRequest request, Network network) {
+ public void onAvailable(Network network) {
currentNetwork = network;
Log.d(TAG, "startUsingNetworkFeature got Network:" + network);
- network.bindProcessForHostResolution();
+ setProcessDefaultNetworkForHostResolution(network);
}
@Override
- public void onLost(NetworkRequest request, Network network) {
+ public void onLost(Network network) {
if (network.equals(currentNetwork)) {
currentNetwork = null;
- network.unbindProcessForHostResolution();
+ setProcessDefaultNetworkForHostResolution(null);
}
Log.d(TAG, "startUsingNetworkFeature lost Network:" + network);
}
@@ -1018,7 +1024,7 @@
if (l == null) return;
ourSeqNum = l.expireSequenceNumber;
if (l.expireSequenceNumber == sequenceNum) {
- releaseNetworkRequest(l.networkRequest);
+ unregisterNetworkCallback(l.networkCallback);
sLegacyRequests.remove(netCap);
}
}
@@ -1035,7 +1041,7 @@
l.networkCapabilities = netCap;
l.delay = delay;
l.expireSequenceNumber = 0;
- l.networkRequest = sendRequestForNetwork(netCap, l.networkCallbackListener, 0,
+ l.networkRequest = sendRequestForNetwork(netCap, l.networkCallback, 0,
REQUEST, type);
if (l.networkRequest == null) return null;
sLegacyRequests.put(netCap, l);
@@ -1051,11 +1057,11 @@
}
}
- private NetworkRequest removeRequestForFeature(NetworkCapabilities netCap) {
+ private NetworkCallback removeRequestForFeature(NetworkCapabilities netCap) {
synchronized (sLegacyRequests) {
LegacyRequest l = sLegacyRequests.remove(netCap);
if (l == null) return null;
- return l.networkRequest;
+ return l.networkCallback;
}
}
@@ -1071,7 +1077,7 @@
* @return {@code true} on success, {@code false} on failure
*
* @deprecated Deprecated in favor of the {@link #requestNetwork},
- * {@link Network#bindProcess} and {@link Network#socketFactory} api.
+ * {@link #setProcessDefaultNetwork} and {@link Network#getSocketFactory} api.
*/
public boolean requestRouteToHost(int networkType, int hostAddress) {
InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
@@ -1095,7 +1101,7 @@
* @return {@code true} on success, {@code false} on failure
* @hide
* @deprecated Deprecated in favor of the {@link #requestNetwork} and
- * {@link Network#bindProcess} api.
+ * {@link #setProcessDefaultNetwork} api.
*/
public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
byte[] address = hostAddress.getAddress();
@@ -1178,8 +1184,8 @@
}
/**
- * Callback for use with {@link ConnectivityManager#registerNetworkActiveListener} to
- * find out when the current network has gone in to a high power state.
+ * Callback for use with {@link ConnectivityManager#registerDefaultNetworkActiveListener}
+ * to find out when the system default network has gone in to a high power state.
*/
public interface OnNetworkActiveListener {
/**
@@ -1188,7 +1194,7 @@
* operations. Note that this listener only tells you when the network becomes
* active; if at any other time you want to know whether it is active (and thus okay
* to initiate network traffic), you can retrieve its instantaneous state with
- * {@link ConnectivityManager#isNetworkActive}.
+ * {@link ConnectivityManager#isDefaultNetworkActive}.
*/
public void onNetworkActive();
}
@@ -1209,13 +1215,18 @@
= new ArrayMap<OnNetworkActiveListener, INetworkActivityListener>();
/**
- * Start listening to reports when the data network is active, meaning it is
- * a good time to perform network traffic. Use {@link #isNetworkActive()}
- * to determine the current state of the network after registering the listener.
+ * Start listening to reports when the system's default data network is active, meaning it is
+ * a good time to perform network traffic. Use {@link #isDefaultNetworkActive()}
+ * to determine the current state of the system's default network after registering the
+ * listener.
+ * <p>
+ * If the process default network has been set with
+ * {@link ConnectivityManager#setProcessDefaultNetwork} this function will not
+ * reflect the process's default, but the system default.
*
* @param l The listener to be told when the network is active.
*/
- public void registerNetworkActiveListener(final OnNetworkActiveListener l) {
+ public void registerDefaultNetworkActiveListener(final OnNetworkActiveListener l) {
INetworkActivityListener rl = new INetworkActivityListener.Stub() {
@Override
public void onNetworkActive() throws RemoteException {
@@ -1232,11 +1243,11 @@
/**
* Remove network active listener previously registered with
- * {@link #registerNetworkActiveListener}.
+ * {@link #registerDefaultNetworkActiveListener}.
*
* @param l Previously registered listener.
*/
- public void unregisterNetworkActiveListener(OnNetworkActiveListener l) {
+ public void unregisterDefaultNetworkActiveListener(OnNetworkActiveListener l) {
INetworkActivityListener rl = mNetworkActivityListeners.get(l);
if (rl == null) {
throw new IllegalArgumentException("Listener not registered: " + l);
@@ -1255,7 +1266,7 @@
* this state. This method tells you whether right now is currently a good time to
* initiate network traffic, as the network is already active.
*/
- public boolean isNetworkActive() {
+ public boolean isDefaultNetworkActive() {
try {
return getNetworkManagementService().isNetworkActive();
} catch (RemoteException e) {
@@ -1887,7 +1898,7 @@
* Base class for NetworkRequest callbacks. Used for notifications about network
* changes. Should be extended by applications wanting notifications.
*/
- public static class NetworkCallbackListener {
+ public static class NetworkCallback {
/** @hide */
public static final int PRECHECK = 1;
/** @hide */
@@ -1910,78 +1921,68 @@
* Called whenever the framework connects to a network that it may use to
* satisfy this request
*/
- public void onPreCheck(NetworkRequest networkRequest, Network network) {}
+ public void onPreCheck(Network network) {}
/**
* Called when the framework connects and has declared new network ready for use.
+ * This callback may be called more than once if the {@link Network} that is
+ * satisfying the request changes.
*
- * @param networkRequest The {@link NetworkRequest} used to initiate the request.
* @param network The {@link Network} of the satisfying network.
*/
- public void onAvailable(NetworkRequest networkRequest, Network network) {}
+ public void onAvailable(Network network) {}
/**
* Called when the network is about to be disconnected. Often paired with an
- * {@link NetworkCallbackListener#onAvailable} call with the new replacement network
+ * {@link NetworkCallback#onAvailable} call with the new replacement network
* for graceful handover. This may not be called if we have a hard loss
* (loss without warning). This may be followed by either a
- * {@link NetworkCallbackListener#onLost} call or a
- * {@link NetworkCallbackListener#onAvailable} call for this network depending
+ * {@link NetworkCallback#onLost} call or a
+ * {@link NetworkCallback#onAvailable} call for this network depending
* on whether we lose or regain it.
*
- * @param networkRequest The {@link NetworkRequest} used to initiate the request.
- * @param network The {@link Network} of the failing network.
- * @param maxSecToLive The time in seconds the framework will attempt to keep the
- * network connected. Note that the network may suffers a
+ * @param network The {@link Network} that is about to be disconnected.
+ * @param maxMsToLive The time in ms the framework will attempt to keep the
+ * network connected. Note that the network may suffer a
* hard loss at any time.
*/
- public void onLosing(NetworkRequest networkRequest, Network network, int maxSecToLive) {}
+ public void onLosing(Network network, int maxMsToLive) {}
/**
* Called when the framework has a hard loss of the network or when the
* graceful failure ends.
*
- * @param networkRequest The {@link NetworkRequest} used to initiate the request.
* @param network The {@link Network} lost.
*/
- public void onLost(NetworkRequest networkRequest, Network network) {}
+ public void onLost(Network network) {}
/**
* Called if no network is found in the given timeout time. If no timeout is given,
* this will not be called.
* @hide
*/
- public void onUnavailable(NetworkRequest networkRequest) {}
+ public void onUnavailable() {}
/**
* Called when the network the framework connected to for this request
* changes capabilities but still satisfies the stated need.
*
- * @param networkRequest The {@link NetworkRequest} used to initiate the request.
* @param network The {@link Network} whose capabilities have changed.
* @param networkCapabilities The new {@link NetworkCapabilities} for this network.
*/
- public void onNetworkCapabilitiesChanged(NetworkRequest networkRequest, Network network,
+ public void onCapabilitiesChanged(Network network,
NetworkCapabilities networkCapabilities) {}
/**
* Called when the network the framework connected to for this request
* changes {@link LinkProperties}.
*
- * @param networkRequest The {@link NetworkRequest} used to initiate the request.
* @param network The {@link Network} whose link properties have changed.
* @param linkProperties The new {@link LinkProperties} for this network.
*/
- public void onLinkPropertiesChanged(NetworkRequest networkRequest, Network network,
- LinkProperties linkProperties) {}
+ public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {}
- /**
- * Called when a {@link #releaseNetworkRequest} call concludes and the registered
- * callbacks will no longer be used.
- *
- * @param networkRequest The {@link NetworkRequest} used to initiate the request.
- */
- public void onReleased(NetworkRequest networkRequest) {}
+ private NetworkRequest networkRequest;
}
private static final int BASE = Protocol.BASE_CONNECTIVITY_MANAGER;
@@ -2007,12 +2008,12 @@
private static final int EXPIRE_LEGACY_REQUEST = BASE + 10;
private class CallbackHandler extends Handler {
- private final HashMap<NetworkRequest, NetworkCallbackListener>mCallbackMap;
+ private final HashMap<NetworkRequest, NetworkCallback>mCallbackMap;
private final AtomicInteger mRefCount;
private static final String TAG = "ConnectivityManager.CallbackHandler";
private final ConnectivityManager mCm;
- CallbackHandler(Looper looper, HashMap<NetworkRequest, NetworkCallbackListener>callbackMap,
+ CallbackHandler(Looper looper, HashMap<NetworkRequest, NetworkCallback>callbackMap,
AtomicInteger refCount, ConnectivityManager cm) {
super(looper);
mCallbackMap = callbackMap;
@@ -2026,9 +2027,9 @@
switch (message.what) {
case CALLBACK_PRECHECK: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbackListener callbacks = getCallbacks(request);
+ NetworkCallback callbacks = getCallbacks(request);
if (callbacks != null) {
- callbacks.onPreCheck(request, getNetwork(message));
+ callbacks.onPreCheck(getNetwork(message));
} else {
Log.e(TAG, "callback not found for PRECHECK message");
}
@@ -2036,9 +2037,9 @@
}
case CALLBACK_AVAILABLE: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbackListener callbacks = getCallbacks(request);
+ NetworkCallback callbacks = getCallbacks(request);
if (callbacks != null) {
- callbacks.onAvailable(request, getNetwork(message));
+ callbacks.onAvailable(getNetwork(message));
} else {
Log.e(TAG, "callback not found for AVAILABLE message");
}
@@ -2046,9 +2047,9 @@
}
case CALLBACK_LOSING: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbackListener callbacks = getCallbacks(request);
+ NetworkCallback callbacks = getCallbacks(request);
if (callbacks != null) {
- callbacks.onLosing(request, getNetwork(message), message.arg1);
+ callbacks.onLosing(getNetwork(message), message.arg1);
} else {
Log.e(TAG, "callback not found for LOSING message");
}
@@ -2056,9 +2057,9 @@
}
case CALLBACK_LOST: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbackListener callbacks = getCallbacks(request);
+ NetworkCallback callbacks = getCallbacks(request);
if (callbacks != null) {
- callbacks.onLost(request, getNetwork(message));
+ callbacks.onLost(getNetwork(message));
} else {
Log.e(TAG, "callback not found for LOST message");
}
@@ -2066,12 +2067,12 @@
}
case CALLBACK_UNAVAIL: {
NetworkRequest req = (NetworkRequest)message.obj;
- NetworkCallbackListener callbacks = null;
+ NetworkCallback callbacks = null;
synchronized(mCallbackMap) {
callbacks = mCallbackMap.get(req);
}
if (callbacks != null) {
- callbacks.onUnavailable(req);
+ callbacks.onUnavailable();
} else {
Log.e(TAG, "callback not found for UNAVAIL message");
}
@@ -2079,12 +2080,12 @@
}
case CALLBACK_CAP_CHANGED: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbackListener callbacks = getCallbacks(request);
+ NetworkCallback callbacks = getCallbacks(request);
if (callbacks != null) {
Network network = getNetwork(message);
NetworkCapabilities cap = mCm.getNetworkCapabilities(network);
- callbacks.onNetworkCapabilitiesChanged(request, network, cap);
+ callbacks.onCapabilitiesChanged(network, cap);
} else {
Log.e(TAG, "callback not found for CHANGED message");
}
@@ -2092,12 +2093,12 @@
}
case CALLBACK_IP_CHANGED: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbackListener callbacks = getCallbacks(request);
+ NetworkCallback callbacks = getCallbacks(request);
if (callbacks != null) {
Network network = getNetwork(message);
LinkProperties lp = mCm.getLinkProperties(network);
- callbacks.onLinkPropertiesChanged(request, network, lp);
+ callbacks.onLinkPropertiesChanged(network, lp);
} else {
Log.e(TAG, "callback not found for CHANGED message");
}
@@ -2105,20 +2106,19 @@
}
case CALLBACK_RELEASED: {
NetworkRequest req = (NetworkRequest)message.obj;
- NetworkCallbackListener callbacks = null;
+ NetworkCallback callbacks = null;
synchronized(mCallbackMap) {
callbacks = mCallbackMap.remove(req);
}
if (callbacks != null) {
- callbacks.onReleased(req);
+ synchronized(mRefCount) {
+ if (mRefCount.decrementAndGet() == 0) {
+ getLooper().quit();
+ }
+ }
} else {
Log.e(TAG, "callback not found for CANCELED message");
}
- synchronized(mRefCount) {
- if (mRefCount.decrementAndGet() == 0) {
- getLooper().quit();
- }
- }
break;
}
case CALLBACK_EXIT: {
@@ -2136,7 +2136,7 @@
private NetworkRequest getNetworkRequest(Message msg) {
return (NetworkRequest)(msg.obj);
}
- private NetworkCallbackListener getCallbacks(NetworkRequest req) {
+ private NetworkCallback getCallbacks(NetworkRequest req) {
synchronized(mCallbackMap) {
return mCallbackMap.get(req);
}
@@ -2144,7 +2144,7 @@
private Network getNetwork(Message msg) {
return new Network(msg.arg2);
}
- private NetworkCallbackListener removeCallbacks(Message msg) {
+ private NetworkCallback removeCallbacks(Message msg) {
NetworkRequest req = (NetworkRequest)msg.obj;
synchronized(mCallbackMap) {
return mCallbackMap.remove(req);
@@ -2152,19 +2152,19 @@
}
}
- private void addCallbackListener() {
+ private void incCallbackHandlerRefCount() {
synchronized(sCallbackRefCount) {
if (sCallbackRefCount.incrementAndGet() == 1) {
// TODO - switch this over to a ManagerThread or expire it when done
HandlerThread callbackThread = new HandlerThread("ConnectivityManager");
callbackThread.start();
sCallbackHandler = new CallbackHandler(callbackThread.getLooper(),
- sNetworkCallbackListener, sCallbackRefCount, this);
+ sNetworkCallback, sCallbackRefCount, this);
}
}
}
- private void removeCallbackListener() {
+ private void decCallbackHandlerRefCount() {
synchronized(sCallbackRefCount) {
if (sCallbackRefCount.decrementAndGet() == 0) {
sCallbackHandler.obtainMessage(CALLBACK_EXIT).sendToTarget();
@@ -2173,8 +2173,8 @@
}
}
- static final HashMap<NetworkRequest, NetworkCallbackListener> sNetworkCallbackListener =
- new HashMap<NetworkRequest, NetworkCallbackListener>();
+ static final HashMap<NetworkRequest, NetworkCallback> sNetworkCallback =
+ new HashMap<NetworkRequest, NetworkCallback>();
static final AtomicInteger sCallbackRefCount = new AtomicInteger(0);
static CallbackHandler sCallbackHandler = null;
@@ -2182,51 +2182,48 @@
private final static int REQUEST = 2;
private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
- NetworkCallbackListener networkCallbackListener, int timeoutSec, int action,
+ NetworkCallback networkCallback, int timeoutSec, int action,
int legacyType) {
- NetworkRequest networkRequest = null;
- if (networkCallbackListener == null) {
- throw new IllegalArgumentException("null NetworkCallbackListener");
+ if (networkCallback == null) {
+ throw new IllegalArgumentException("null NetworkCallback");
}
if (need == null) throw new IllegalArgumentException("null NetworkCapabilities");
try {
- addCallbackListener();
+ incCallbackHandlerRefCount();
if (action == LISTEN) {
- networkRequest = mService.listenForNetwork(need, new Messenger(sCallbackHandler),
- new Binder());
+ networkCallback.networkRequest = mService.listenForNetwork(need,
+ new Messenger(sCallbackHandler), new Binder());
} else {
- networkRequest = mService.requestNetwork(need, new Messenger(sCallbackHandler),
- timeoutSec, new Binder(), legacyType);
+ networkCallback.networkRequest = mService.requestNetwork(need,
+ new Messenger(sCallbackHandler), timeoutSec, new Binder(), legacyType);
}
- if (networkRequest != null) {
- synchronized(sNetworkCallbackListener) {
- sNetworkCallbackListener.put(networkRequest, networkCallbackListener);
+ if (networkCallback.networkRequest != null) {
+ synchronized(sNetworkCallback) {
+ sNetworkCallback.put(networkCallback.networkRequest, networkCallback);
}
}
} catch (RemoteException e) {}
- if (networkRequest == null) removeCallbackListener();
- return networkRequest;
+ if (networkCallback.networkRequest == null) decCallbackHandlerRefCount();
+ return networkCallback.networkRequest;
}
/**
* Request a network to satisfy a set of {@link NetworkCapabilities}.
*
* This {@link NetworkRequest} will live until released via
- * {@link #releaseNetworkRequest} or the calling application exits.
+ * {@link #unregisterNetworkCallback} or the calling application exits.
* Status of the request can be followed by listening to the various
- * callbacks described in {@link NetworkCallbackListener}. The {@link Network}
+ * callbacks described in {@link NetworkCallback}. The {@link Network}
* can be used to direct traffic to the network.
*
- * @param need {@link NetworkCapabilities} required by this request.
- * @param networkCallbackListener The {@link NetworkCallbackListener} to be utilized for this
- * request. Note the callbacks can be shared by multiple
- * requests and the NetworkRequest token utilized to
- * determine to which request the callback relates.
- * @return A {@link NetworkRequest} object identifying the request.
+ * @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this
+ * request. Note the callback must not be shared - they
+ * uniquely specify this request.
*/
- public NetworkRequest requestNetwork(NetworkCapabilities need,
- NetworkCallbackListener networkCallbackListener) {
- return sendRequestForNetwork(need, networkCallbackListener, 0, REQUEST, TYPE_NONE);
+ public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback) {
+ sendRequestForNetwork(request.networkCapabilities, networkCallback, 0,
+ REQUEST, TYPE_NONE);
}
/**
@@ -2234,53 +2231,53 @@
* by a timeout.
*
* This function behaves identically to the non-timedout version, but if a suitable
- * network is not found within the given time (in Seconds) the
- * {@link NetworkCallbackListener#unavailable} callback is called. The request must
+ * network is not found within the given time (in milliseconds) the
+ * {@link NetworkCallback#unavailable} callback is called. The request must
* still be released normally by calling {@link releaseNetworkRequest}.
- * @param need {@link NetworkCapabilities} required by this request.
- * @param networkCallbackListener The callbacks to be utilized for this request. Note
- * the callbacks can be shared by multiple requests and
- * the NetworkRequest token utilized to determine to which
- * request the callback relates.
- * @param timeoutSec The time in seconds to attempt looking for a suitable network
- * before {@link NetworkCallbackListener#unavailable} is called.
- * @return A {@link NetworkRequest} object identifying the request.
+ * @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The callbacks to be utilized for this request. Note
+ * the callbacks must not be shared - they uniquely specify
+ * this request.
+ * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
+ * before {@link NetworkCallback#unavailable} is called.
* @hide
*/
- public NetworkRequest requestNetwork(NetworkCapabilities need,
- NetworkCallbackListener networkCallbackListener, int timeoutSec) {
- return sendRequestForNetwork(need, networkCallbackListener, timeoutSec, REQUEST,
- TYPE_NONE);
+ public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
+ int timeoutMs) {
+ sendRequestForNetwork(request.networkCapabilities, networkCallback, timeoutMs,
+ REQUEST, TYPE_NONE);
}
/**
- * The maximum number of seconds the framework will look for a suitable network
+ * The maximum number of milliseconds the framework will look for a suitable network
* during a timeout-equiped call to {@link requestNetwork}.
* {@hide}
*/
- public final static int MAX_NETWORK_REQUEST_TIMEOUT_SEC = 100 * 60;
+ public final static int MAX_NETWORK_REQUEST_TIMEOUT_MS = 100 * 60 * 1000;
/**
* The lookup key for a {@link Network} object included with the intent after
* succesfully finding a network for the applications request. Retrieve it with
* {@link android.content.Intent#getParcelableExtra(String)}.
+ * @hide
*/
public static final String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork";
/**
- * The lookup key for a {@link NetworkCapabilities} object included with the intent after
+ * The lookup key for a {@link NetworkRequest} object included with the intent after
* succesfully finding a network for the applications request. Retrieve it with
* {@link android.content.Intent#getParcelableExtra(String)}.
+ * @hide
*/
- public static final String EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES =
- "networkRequestNetworkCapabilities";
+ public static final String EXTRA_NETWORK_REQUEST_NETWORK_REQUEST =
+ "networkRequestNetworkRequest";
/**
* Request a network to satisfy a set of {@link NetworkCapabilities}.
*
- * This function behavies identically to the callback-equiped version, but instead
- * of {@link NetworkCallbackListener} a {@link PendingIntent} is used. This means
+ * This function behavies identically to the version that takes a NetworkCallback, but instead
+ * of {@link NetworkCallback} a {@link PendingIntent} is used. This means
* the request may outlive the calling application and get called back when a suitable
* network is found.
* <p>
@@ -2289,10 +2286,10 @@
* <receiver> tag in an AndroidManifest.xml file
* <p>
* The operation Intent is delivered with two extras, a {@link Network} typed
- * extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkCapabilities}
- * typed extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES} containing
+ * extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkRequest}
+ * typed extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK_REQUEST} containing
* the original requests parameters. It is important to create a new,
- * {@link NetworkCallbackListener} based request before completing the processing of the
+ * {@link NetworkCallback} based request before completing the processing of the
* Intent to reserve the network or it will be released shortly after the Intent
* is processed.
* <p>
@@ -2300,51 +2297,109 @@
* two Intents defined by {@link Intent#filterEquals}), then it will be removed and
* replaced by this one, effectively releasing the previous {@link NetworkRequest}.
* <p>
- * The request may be released normally by calling {@link #releaseNetworkRequest}.
+ * The request may be released normally by calling {@link #unregisterNetworkCallback}.
*
- * @param need {@link NetworkCapabilities} required by this request.
+ * @param request {@link NetworkRequest} describing this request.
* @param operation Action to perform when the network is available (corresponds
- * to the {@link NetworkCallbackListener#onAvailable} call. Typically
+ * to the {@link NetworkCallback#onAvailable} call. Typically
* comes from {@link PendingIntent#getBroadcast}.
- * @return A {@link NetworkRequest} object identifying the request.
+ * @hide
*/
- public NetworkRequest requestNetwork(NetworkCapabilities need, PendingIntent operation) {
+ public void requestNetwork(NetworkRequest request, PendingIntent operation) {
try {
- return mService.pendingRequestForNetwork(need, operation);
+ mService.pendingRequestForNetwork(request.networkCapabilities, operation);
} catch (RemoteException e) {}
- return null;
}
/**
* Registers to receive notifications about all networks which satisfy the given
- * {@link NetworkCapabilities}. The callbacks will continue to be called until
- * either the application exits or the request is released using
- * {@link #releaseNetworkRequest}.
+ * {@link NetworkRequest}. The callbacks will continue to be called until
+ * either the application exits or {@link #unregisterNetworkCallback} is called
*
- * @param need {@link NetworkCapabilities} required by this request.
- * @param networkCallbackListener The {@link NetworkCallbackListener} to be called as suitable
- * networks change state.
- * @return A {@link NetworkRequest} object identifying the request.
+ * @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
+ * networks change state.
*/
- public NetworkRequest listenForNetwork(NetworkCapabilities need,
- NetworkCallbackListener networkCallbackListener) {
- return sendRequestForNetwork(need, networkCallbackListener, 0, LISTEN, TYPE_NONE);
+ public void registerNetworkCallback(NetworkRequest request, NetworkCallback networkCallback) {
+ sendRequestForNetwork(request.networkCapabilities, networkCallback, 0, LISTEN, TYPE_NONE);
}
/**
- * Releases a {@link NetworkRequest} generated either through a {@link #requestNetwork}
- * or a {@link #listenForNetwork} call. The {@link NetworkCallbackListener} given in the
- * earlier call may continue receiving calls until the
- * {@link NetworkCallbackListener#onReleased} function is called, signifying the end
- * of the request.
+ * Unregisters callbacks about and possibly releases networks originating from
+ * {@link #requestNetwork} and {@link #registerNetworkCallback} calls. If the
+ * given {@code NetworkCallback} had previosuly been used with {@code #requestNetwork},
+ * any networks that had been connected to only to satisfy that request will be
+ * disconnected.
*
- * @param networkRequest The {@link NetworkRequest} generated by an earlier call to
- * {@link #requestNetwork} or {@link #listenForNetwork}.
+ * @param networkCallback The {@link NetworkCallback} used when making the request.
*/
- public void releaseNetworkRequest(NetworkRequest networkRequest) {
- if (networkRequest == null) throw new IllegalArgumentException("null NetworkRequest");
+ public void unregisterNetworkCallback(NetworkCallback networkCallback) {
+ if (networkCallback == null || networkCallback.networkRequest == null ||
+ networkCallback.networkRequest.requestId == REQUEST_ID_UNSET) {
+ throw new IllegalArgumentException("Invalid NetworkCallback");
+ }
try {
- mService.releaseNetworkRequest(networkRequest);
+ mService.releaseNetworkRequest(networkCallback.networkRequest);
} catch (RemoteException e) {}
}
+
+ /**
+ * Binds the current process to {@code network}. All Sockets created in the future
+ * (and not explicitly bound via a bound SocketFactory from
+ * {@link Network#getSocketFactory() Network.getSocketFactory()}) will be bound to
+ * {@code network}. All host name resolutions will be limited to {@code network} as well.
+ * Note that if {@code network} ever disconnects, all Sockets created in this way will cease to
+ * work and all host name resolutions will fail. This is by design so an application doesn't
+ * accidentally use Sockets it thinks are still bound to a particular {@link Network}.
+ * To clear binding pass {@code null} for {@code network}. Using individually bound
+ * Sockets created by Network.getSocketFactory().createSocket() and
+ * performing network-specific host name resolutions via
+ * {@link Network#getAllByName Network.getAllByName} is preferred to calling
+ * {@code setProcessDefaultNetwork}.
+ *
+ * @param network The {@link Network} to bind the current process to, or {@code null} to clear
+ * the current binding.
+ * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
+ */
+ public static boolean setProcessDefaultNetwork(Network network) {
+ if (network == null) {
+ NetworkUtils.unbindProcessToNetwork();
+ } else {
+ NetworkUtils.bindProcessToNetwork(network.netId);
+ }
+ // TODO fix return value
+ return true;
+ }
+
+ /**
+ * Returns the {@link Network} currently bound to this process via
+ * {@link #setProcessDefaultNetwork}, or {@code null} if no {@link Network} is explicitly bound.
+ *
+ * @return {@code Network} to which this process is bound, or {@code null}.
+ */
+ public static Network getProcessDefaultNetwork() {
+ int netId = NetworkUtils.getNetworkBoundToProcess();
+ if (netId == 0) return null;
+ return new Network(netId);
+ }
+
+ /**
+ * Binds host resolutions performed by this process to {@code network}.
+ * {@link #setProcessDefaultNetwork} takes precedence over this setting.
+ *
+ * @param network The {@link Network} to bind host resolutions from the current process to, or
+ * {@code null} to clear the current binding.
+ * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
+ * @hide
+ * @deprecated This is strictly for legacy usage to support {@link #startUsingNetworkFeature}.
+ */
+ public static boolean setProcessDefaultNetworkForHostResolution(Network network) {
+ if (network == null) {
+ NetworkUtils.unbindProcessToNetworkForHostResolution();
+ } else {
+ NetworkUtils.bindProcessToNetworkForHostResolution(network.netId);
+ }
+ // TODO hook up the return value.
+ return true;
+ }
}
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index 22b26b1..49a307e 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -74,8 +74,10 @@
if (linkProperties.getRoutes().size() == 0) {
for (RouteInfo r : orig.linkProperties.getRoutes()) linkProperties.addRoute(r);
}
- if (linkProperties.getDnses().size() == 0) {
- for (InetAddress d : orig.linkProperties.getDnses()) linkProperties.addDns(d);
+ if (linkProperties.getDnsServers().size() == 0) {
+ for (InetAddress d : orig.linkProperties.getDnsServers()) {
+ linkProperties.addDnsServer(d);
+ }
}
}
@@ -211,7 +213,7 @@
public boolean addDns(String addrString) {
if (TextUtils.isEmpty(addrString) == false) {
try {
- linkProperties.addDns(NetworkUtils.numericToInetAddress(addrString));
+ linkProperties.addDnsServer(NetworkUtils.numericToInetAddress(addrString));
} catch (IllegalArgumentException e) {
Log.e(TAG, "addDns failed with addrString " + addrString);
return true;
diff --git a/core/java/android/net/DnsPinger.java b/core/java/android/net/DnsPinger.java
index 66f0fd0..7acf3f5 100644
--- a/core/java/android/net/DnsPinger.java
+++ b/core/java/android/net/DnsPinger.java
@@ -248,7 +248,7 @@
return mDefaultDns;
}
- Collection<InetAddress> dnses = curLinkProps.getDnses();
+ Collection<InetAddress> dnses = curLinkProps.getDnsServers();
if (dnses == null || dnses.size() == 0) {
loge("getDns::LinkProps has null dns - returning default");
return mDefaultDns;
diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl
index dd9c39f..b7af374 100644
--- a/core/java/android/net/INetworkManagementEventObserver.aidl
+++ b/core/java/android/net/INetworkManagementEventObserver.aidl
@@ -17,6 +17,7 @@
package android.net;
import android.net.LinkAddress;
+import android.net.RouteInfo;
/**
* Callback class for receiving events from an INetworkManagementService
@@ -98,4 +99,14 @@
* @param servers The IP addresses of the DNS servers.
*/
void interfaceDnsServerInfo(String iface, long lifetime, in String[] servers);
+
+ /**
+ * A route has been added or updated.
+ */
+ void routeUpdated(in RouteInfo route);
+
+ /**
+ * A route has been removed.
+ */
+ void routeRemoved(in RouteInfo route);
}
diff --git a/core/java/android/app/task/Task.aidl b/core/java/android/net/IpPrefix.aidl
similarity index 85%
copy from core/java/android/app/task/Task.aidl
copy to core/java/android/net/IpPrefix.aidl
index 1f25439..9e552c7 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/core/java/android/net/IpPrefix.aidl
@@ -1,11 +1,12 @@
/**
+ *
* 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
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,7 +15,6 @@
* limitations under the License.
*/
-package android.app.task;
+package android.net;
-parcelable Task;
-
\ No newline at end of file
+parcelable IpPrefix;
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
new file mode 100644
index 0000000..f1fa3eb
--- /dev/null
+++ b/core/java/android/net/IpPrefix.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Pair;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
+/**
+ * This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a
+ * power of two boundary (also known as an "IP subnet"). A prefix is specified by two pieces of
+ * information:
+ *
+ * <ul>
+ * <li>A starting IP address (IPv4 or IPv6). This is the first IP address of the prefix.
+ * <li>A prefix length. This specifies the length of the prefix by specifing the number of bits
+ * in the IP address, starting from the most significant bit in network byte order, that
+ * are constant for all addresses in the prefix.
+ * </ul>
+ *
+ * For example, the prefix <code>192.0.2.0/24</code> covers the 256 IPv4 addresses from
+ * <code>192.0.2.0</code> to <code>192.0.2.255</code>, inclusive, and the prefix
+ * <code>2001:db8:1:2</code> covers the 2^64 IPv6 addresses from <code>2001:db8:1:2::</code> to
+ * <code>2001:db8:1:2:ffff:ffff:ffff:ffff</code>, inclusive.
+ *
+ * Objects of this class are immutable.
+ */
+public final class IpPrefix implements Parcelable {
+ private final byte[] address; // network byte order
+ private final int prefixLength;
+
+ private void checkAndMaskAddressAndPrefixLength() {
+ if (address.length != 4 && address.length != 16) {
+ throw new IllegalArgumentException(
+ "IpPrefix has " + address.length + " bytes which is neither 4 nor 16");
+ }
+ NetworkUtils.maskRawAddress(address, prefixLength);
+ }
+
+ /**
+ * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in
+ * network byte order and a prefix length. Silently truncates the address to the prefix length,
+ * so for example {@code 192.0.2.1/24} is silently converted to {@code 192.0.2.0/24}.
+ *
+ * @param address the IP address. Must be non-null and exactly 4 or 16 bytes long.
+ * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
+ *
+ * @hide
+ */
+ public IpPrefix(byte[] address, int prefixLength) {
+ this.address = address.clone();
+ this.prefixLength = prefixLength;
+ checkAndMaskAddressAndPrefixLength();
+ }
+
+ /**
+ * Constructs a new {@code IpPrefix} from an IPv4 or IPv6 address and a prefix length. Silently
+ * truncates the address to the prefix length, so for example {@code 192.0.2.1/24} is silently
+ * converted to {@code 192.0.2.0/24}.
+ *
+ * @param address the IP address. Must be non-null.
+ * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
+ * @hide
+ */
+ public IpPrefix(InetAddress address, int prefixLength) {
+ // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array,
+ // which is unnecessary because getAddress() already returns a clone.
+ this.address = address.getAddress();
+ this.prefixLength = prefixLength;
+ checkAndMaskAddressAndPrefixLength();
+ }
+
+ /**
+ * Constructs a new IpPrefix from a string such as "192.0.2.1/24" or "2001:db8::1/64".
+ * Silently truncates the address to the prefix length, so for example {@code 192.0.2.1/24}
+ * is silently converted to {@code 192.0.2.0/24}.
+ *
+ * @param prefix the prefix to parse
+ *
+ * @hide
+ */
+ public IpPrefix(String prefix) {
+ // We don't reuse the (InetAddress, int) constructor because "error: call to this must be
+ // first statement in constructor". We could factor out setting the member variables to an
+ // init() method, but if we did, then we'd have to make the members non-final, or "error:
+ // cannot assign a value to final variable address". So we just duplicate the code here.
+ Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(prefix);
+ this.address = ipAndMask.first.getAddress();
+ this.prefixLength = ipAndMask.second;
+ checkAndMaskAddressAndPrefixLength();
+ }
+
+ /**
+ * Compares this {@code IpPrefix} object against the specified object in {@code obj}. Two
+ * objects are equal if they have the same startAddress and prefixLength.
+ *
+ * @param obj the object to be tested for equality.
+ * @return {@code true} if both objects are equal, {@code false} otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof IpPrefix)) {
+ return false;
+ }
+ IpPrefix that = (IpPrefix) obj;
+ return Arrays.equals(this.address, that.address) && this.prefixLength == that.prefixLength;
+ }
+
+ /**
+ * Gets the hashcode of the represented IP prefix.
+ *
+ * @return the appropriate hashcode value.
+ */
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(address) + 11 * prefixLength;
+ }
+
+ /**
+ * Returns a copy of the first IP address in the prefix. Modifying the returned object does not
+ * change this object's contents.
+ *
+ * @return the address in the form of a byte array.
+ */
+ public InetAddress getAddress() {
+ try {
+ return InetAddress.getByAddress(address);
+ } catch (UnknownHostException e) {
+ // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte
+ // array is the wrong length, but we check that in the constructor.
+ return null;
+ }
+ }
+
+ /**
+ * Returns a copy of the IP address bytes in network order (the highest order byte is the zeroth
+ * element). Modifying the returned array does not change this object's contents.
+ *
+ * @return the address in the form of a byte array.
+ */
+ public byte[] getRawAddress() {
+ return address.clone();
+ }
+
+ /**
+ * Returns the prefix length of this {@code IpPrefix}.
+ *
+ * @return the prefix length.
+ */
+ public int getPrefixLength() {
+ return prefixLength;
+ }
+
+ /**
+ * Returns a string representation of this {@code IpPrefix}.
+ *
+ * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::"}.
+ */
+ public String toString() {
+ try {
+ return InetAddress.getByAddress(address).getHostAddress() + "/" + prefixLength;
+ } catch(UnknownHostException e) {
+ // Cosmic rays?
+ throw new IllegalStateException("IpPrefix with invalid address! Shouldn't happen.", e);
+ }
+ }
+
+ /**
+ * Implement the Parcelable interface.
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Implement the Parcelable interface.
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByteArray(address);
+ dest.writeInt(prefixLength);
+ }
+
+ /**
+ * Implement the Parcelable interface.
+ */
+ public static final Creator<IpPrefix> CREATOR =
+ new Creator<IpPrefix>() {
+ public IpPrefix createFromParcel(Parcel in) {
+ byte[] address = in.createByteArray();
+ int prefixLength = in.readInt();
+ return new IpPrefix(address, prefixLength);
+ }
+
+ public IpPrefix[] newArray(int size) {
+ return new IpPrefix[size];
+ }
+ };
+}
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index d07c0b61..f9a25f9 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -18,6 +18,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Pair;
import java.net.Inet4Address;
import java.net.InetAddress;
@@ -39,18 +40,13 @@
* <ul>
* <li>An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}).
* The address must be unicast, as multicast addresses cannot be assigned to interfaces.
- * <li>Address flags: A bitmask of {@code IFA_F_*} values representing properties
- * of the address.
- * <li>Address scope: An integer defining the scope in which the address is unique (e.g.,
- * {@code RT_SCOPE_LINK} or {@code RT_SCOPE_SITE}).
- * <ul>
- *<p>
- * When constructing a {@code LinkAddress}, the IP address and prefix are required. The flags and
- * scope are optional. If they are not specified, the flags are set to zero, and the scope will be
- * determined based on the IP address (e.g., link-local addresses will be created with a scope of
- * {@code RT_SCOPE_LINK}, global addresses with {@code RT_SCOPE_UNIVERSE},
- * etc.) If they are specified, they are not checked for validity.
- *
+ * <li>Address flags: A bitmask of {@code OsConstants.IFA_F_*} values representing properties
+ * of the address (e.g., {@code android.system.OsConstants.IFA_F_OPTIMISTIC}).
+ * <li>Address scope: One of the {@code OsConstants.IFA_F_*} values; defines the scope in which
+ * the address is unique (e.g.,
+ * {@code android.system.OsConstants.RT_SCOPE_LINK} or
+ * {@code android.system.OsConstants.RT_SCOPE_UNIVERSE}).
+ * </ul>
*/
public class LinkAddress implements Parcelable {
/**
@@ -171,23 +167,9 @@
* @hide
*/
public LinkAddress(String address, int flags, int scope) {
- InetAddress inetAddress = null;
- int prefixLength = -1;
- try {
- String [] pieces = address.split("/", 2);
- prefixLength = Integer.parseInt(pieces[1]);
- inetAddress = InetAddress.parseNumericAddress(pieces[0]);
- } catch (NullPointerException e) { // Null string.
- } catch (ArrayIndexOutOfBoundsException e) { // No prefix length.
- } catch (NumberFormatException e) { // Non-numeric prefix.
- } catch (IllegalArgumentException e) { // Invalid IP address.
- }
-
- if (inetAddress == null || prefixLength == -1) {
- throw new IllegalArgumentException("Bad LinkAddress params " + address);
- }
-
- init(inetAddress, prefixLength, flags, scope);
+ // This may throw an IllegalArgumentException; catching it is the caller's responsibility.
+ Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address);
+ init(ipAndMask.first, ipAndMask.second, flags, scope);
}
/**
@@ -202,7 +184,9 @@
/**
* Compares this {@code LinkAddress} instance against {@code obj}. Two addresses are equal if
- * their address, prefix length, flags and scope are equal.
+ * their address, prefix length, flags and scope are equal. Thus, for example, two addresses
+ * that have the same address and prefix length are not equal if one of them is deprecated and
+ * the other is not.
*
* @param obj the object to be tested for equality.
* @return {@code true} if both objects are equal, {@code false} otherwise.
@@ -236,6 +220,7 @@
* @param other the {@code LinkAddress} to compare to.
* @return {@code true} if both objects have the same address and prefix length, {@code false}
* otherwise.
+ * @hide
*/
public boolean isSameAddressAs(LinkAddress other) {
return address.equals(other.address) && prefixLength == other.prefixLength;
@@ -251,11 +236,20 @@
/**
* Returns the prefix length of this {@code LinkAddress}.
*/
- public int getNetworkPrefixLength() {
+ public int getPrefixLength() {
return prefixLength;
}
/**
+ * Returns the prefix length of this {@code LinkAddress}.
+ * TODO: Delete all callers and remove in favour of getPrefixLength().
+ * @hide
+ */
+ public int getNetworkPrefixLength() {
+ return getPrefixLength();
+ }
+
+ /**
* Returns the flags of this {@code LinkAddress}.
*/
public int getFlags() {
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 3c36679..e7184ed 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -30,6 +30,8 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Hashtable;
+import java.util.List;
+import java.util.Objects;
/**
* Describes the properties of a network link.
@@ -43,7 +45,7 @@
* does not affect live networks.
*
*/
-public class LinkProperties implements Parcelable {
+public final class LinkProperties implements Parcelable {
// The interface described by the network link.
private String mIfaceName;
private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
@@ -58,10 +60,12 @@
private Hashtable<String, LinkProperties> mStackedLinks =
new Hashtable<String, LinkProperties>();
- // @hide
+ /**
+ * @hide
+ */
public static class CompareResult<T> {
- public Collection<T> removed = new ArrayList<T>();
- public Collection<T> added = new ArrayList<T>();
+ public List<T> removed = new ArrayList<T>();
+ public List<T> added = new ArrayList<T>();
@Override
public String toString() {
@@ -74,14 +78,20 @@
}
}
+ /**
+ * @hide
+ */
public LinkProperties() {
}
+ /**
+ * @hide
+ */
public LinkProperties(LinkProperties source) {
if (source != null) {
mIfaceName = source.getInterfaceName();
for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l);
- for (InetAddress i : source.getDnses()) mDnses.add(i);
+ for (InetAddress i : source.getDnsServers()) mDnses.add(i);
mDomains = source.getDomains();
for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
mHttpProxy = (source.getHttpProxy() == null) ?
@@ -98,6 +108,7 @@
* will have their interface changed to match this new value.
*
* @param iface The name of the network interface used for this link.
+ * @hide
*/
public void setInterfaceName(String iface) {
mIfaceName = iface;
@@ -117,9 +128,11 @@
return mIfaceName;
}
- // @hide
- public Collection<String> getAllInterfaceNames() {
- Collection interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1);
+ /**
+ * @hide
+ */
+ public List<String> getAllInterfaceNames() {
+ List<String> interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1);
if (mIfaceName != null) interfaceNames.add(new String(mIfaceName));
for (LinkProperties stacked: mStackedLinks.values()) {
interfaceNames.addAll(stacked.getAllInterfaceNames());
@@ -134,23 +147,23 @@
* prefix lengths for each address. This is a simplified utility alternative to
* {@link LinkProperties#getLinkAddresses}.
*
- * @return An umodifiable {@link Collection} of {@link InetAddress} for this link.
+ * @return An umodifiable {@link List} of {@link InetAddress} for this link.
* @hide
*/
- public Collection<InetAddress> getAddresses() {
- Collection<InetAddress> addresses = new ArrayList<InetAddress>();
+ public List<InetAddress> getAddresses() {
+ List<InetAddress> addresses = new ArrayList<InetAddress>();
for (LinkAddress linkAddress : mLinkAddresses) {
addresses.add(linkAddress.getAddress());
}
- return Collections.unmodifiableCollection(addresses);
+ return Collections.unmodifiableList(addresses);
}
/**
* Returns all the addresses on this link and all the links stacked above it.
* @hide
*/
- public Collection<InetAddress> getAllAddresses() {
- Collection<InetAddress> addresses = new ArrayList<InetAddress>();
+ public List<InetAddress> getAllAddresses() {
+ List<InetAddress> addresses = new ArrayList<InetAddress>();
for (LinkAddress linkAddress : mLinkAddresses) {
addresses.add(linkAddress.getAddress());
}
@@ -174,6 +187,7 @@
* same address/prefix does not already exist. If it does exist it is replaced.
* @param address The {@code LinkAddress} to add.
* @return true if {@code address} was added or updated, false otherwise.
+ * @hide
*/
public boolean addLinkAddress(LinkAddress address) {
if (address == null) {
@@ -200,6 +214,7 @@
*
* @param toRemove A {@link LinkAddress} specifying the address to remove.
* @return true if the address was removed, false if it did not exist.
+ * @hide
*/
public boolean removeLinkAddress(LinkAddress toRemove) {
int i = findLinkAddressIndex(toRemove);
@@ -214,18 +229,18 @@
* Returns all the {@link LinkAddress} on this link. Typically a link will have
* one IPv4 address and one or more IPv6 addresses.
*
- * @return An unmodifiable {@link Collection} of {@link LinkAddress} for this link.
+ * @return An unmodifiable {@link List} of {@link LinkAddress} for this link.
*/
- public Collection<LinkAddress> getLinkAddresses() {
- return Collections.unmodifiableCollection(mLinkAddresses);
+ public List<LinkAddress> getLinkAddresses() {
+ return Collections.unmodifiableList(mLinkAddresses);
}
/**
* Returns all the addresses on this link and all the links stacked above it.
* @hide
*/
- public Collection<LinkAddress> getAllLinkAddresses() {
- Collection<LinkAddress> addresses = new ArrayList<LinkAddress>();
+ public List<LinkAddress> getAllLinkAddresses() {
+ List<LinkAddress> addresses = new ArrayList<LinkAddress>();
addresses.addAll(mLinkAddresses);
for (LinkProperties stacked: mStackedLinks.values()) {
addresses.addAll(stacked.getAllLinkAddresses());
@@ -239,6 +254,7 @@
*
* @param addresses The {@link Collection} of {@link LinkAddress} to set in this
* object.
+ * @hide
*/
public void setLinkAddresses(Collection<LinkAddress> addresses) {
mLinkAddresses.clear();
@@ -250,20 +266,21 @@
/**
* Adds the given {@link InetAddress} to the list of DNS servers.
*
- * @param dns The {@link InetAddress} to add to the list of DNS servers.
+ * @param dnsServer The {@link InetAddress} to add to the list of DNS servers.
+ * @hide
*/
- public void addDns(InetAddress dns) {
- if (dns != null) mDnses.add(dns);
+ public void addDnsServer(InetAddress dnsServer) {
+ if (dnsServer != null) mDnses.add(dnsServer);
}
/**
- * Returns all the {@link LinkAddress} for DNS servers on this link.
+ * Returns all the {@link InetAddress} for DNS servers on this link.
*
- * @return An umodifiable {@link Collection} of {@link InetAddress} for DNS servers on
+ * @return An umodifiable {@link List} of {@link InetAddress} for DNS servers on
* this link.
*/
- public Collection<InetAddress> getDnses() {
- return Collections.unmodifiableCollection(mDnses);
+ public List<InetAddress> getDnsServers() {
+ return Collections.unmodifiableList(mDnses);
}
/**
@@ -271,6 +288,7 @@
*
* @param domains A {@link String} listing in priority order the comma separated
* domains to search when resolving host names on this link.
+ * @hide
*/
public void setDomains(String domains) {
mDomains = domains;
@@ -317,14 +335,17 @@
}
/**
- * Adds a {@link RouteInfo} to this {@code LinkProperties}. If the {@link RouteInfo}
- * had an interface name set and that differs from the interface set for this
- * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown. The
- * proper course is to add either un-named or properly named {@link RouteInfo}.
+ * Adds a {@link RouteInfo} to this {@code LinkProperties}, if not present. If the
+ * {@link RouteInfo} had an interface name set and that differs from the interface set for this
+ * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown. The proper
+ * course is to add either un-named or properly named {@link RouteInfo}.
*
* @param route A {@link RouteInfo} to add to this object.
+ * @return {@code false} if the route was already present, {@code true} if it was added.
+ *
+ * @hide
*/
- public void addRoute(RouteInfo route) {
+ public boolean addRoute(RouteInfo route) {
if (route != null) {
String routeIface = route.getInterface();
if (routeIface != null && !routeIface.equals(mIfaceName)) {
@@ -332,25 +353,45 @@
"Route added with non-matching interface: " + routeIface +
" vs. " + mIfaceName);
}
- mRoutes.add(routeWithInterface(route));
+ route = routeWithInterface(route);
+ if (!mRoutes.contains(route)) {
+ mRoutes.add(route);
+ return true;
+ }
}
+ return false;
+ }
+
+ /**
+ * Removes a {@link RouteInfo} from this {@code LinkProperties}, if present. The route must
+ * specify an interface and the interface must match the interface of this
+ * {@code LinkProperties}, or it will not be removed.
+ *
+ * @return {@code true} if the route was removed, {@code false} if it was not present.
+ *
+ * @hide
+ */
+ public boolean removeRoute(RouteInfo route) {
+ return route != null &&
+ Objects.equals(mIfaceName, route.getInterface()) &&
+ mRoutes.remove(route);
}
/**
* Returns all the {@link RouteInfo} set on this link.
*
- * @return An unmodifiable {@link Collection} of {@link RouteInfo} for this link.
+ * @return An unmodifiable {@link List} of {@link RouteInfo} for this link.
*/
- public Collection<RouteInfo> getRoutes() {
- return Collections.unmodifiableCollection(mRoutes);
+ public List<RouteInfo> getRoutes() {
+ return Collections.unmodifiableList(mRoutes);
}
/**
* Returns all the routes on this link and all the links stacked above it.
* @hide
*/
- public Collection<RouteInfo> getAllRoutes() {
- Collection<RouteInfo> routes = new ArrayList();
+ public List<RouteInfo> getAllRoutes() {
+ List<RouteInfo> routes = new ArrayList();
routes.addAll(mRoutes);
for (LinkProperties stacked: mStackedLinks.values()) {
routes.addAll(stacked.getAllRoutes());
@@ -364,6 +405,7 @@
* not enforce it and applications may ignore them.
*
* @param proxy A {@link ProxyInfo} defining the Http Proxy to use on this link.
+ * @hide
*/
public void setHttpProxy(ProxyInfo proxy) {
mHttpProxy = proxy;
@@ -419,16 +461,17 @@
* Returns all the links stacked on top of this link.
* @hide
*/
- public Collection<LinkProperties> getStackedLinks() {
- Collection<LinkProperties> stacked = new ArrayList<LinkProperties>();
+ public List<LinkProperties> getStackedLinks() {
+ List<LinkProperties> stacked = new ArrayList<LinkProperties>();
for (LinkProperties link : mStackedLinks.values()) {
stacked.add(new LinkProperties(link));
}
- return Collections.unmodifiableCollection(stacked);
+ return Collections.unmodifiableList(stacked);
}
/**
* Clears this object to its initial state.
+ * @hide
*/
public void clear() {
mIfaceName = null;
@@ -443,7 +486,6 @@
/**
* Implement the Parcelable interface
- * @hide
*/
public int describeContents() {
return 0;
@@ -463,12 +505,12 @@
String domainName = "Domains: " + mDomains;
- String mtu = "MTU: " + mMtu;
+ String mtu = " MTU: " + mMtu;
String routes = " Routes: [";
for (RouteInfo route : mRoutes) routes += route.toString() + ",";
routes += "] ";
- String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
+ String proxy = (mHttpProxy == null ? "" : " HttpProxy: " + mHttpProxy.toString() + " ");
String stacked = "";
if (mStackedLinks.values().size() > 0) {
@@ -486,6 +528,7 @@
* Returns true if this link has an IPv4 address.
*
* @return {@code true} if there is an IPv4 address, {@code false} otherwise.
+ * @hide
*/
public boolean hasIPv4Address() {
for (LinkAddress address : mLinkAddresses) {
@@ -500,6 +543,7 @@
* Returns true if this link has an IPv6 address.
*
* @return {@code true} if there is an IPv6 address, {@code false} otherwise.
+ * @hide
*/
public boolean hasIPv6Address() {
for (LinkAddress address : mLinkAddresses) {
@@ -543,7 +587,7 @@
* @hide
*/
public boolean isIdenticalDnses(LinkProperties target) {
- Collection<InetAddress> targetDnses = target.getDnses();
+ Collection<InetAddress> targetDnses = target.getDnsServers();
String targetDomains = target.getDomains();
if (mDomains == null) {
if (targetDomains != null) return false;
@@ -696,7 +740,7 @@
result.removed = new ArrayList<InetAddress>(mDnses);
result.added.clear();
if (target != null) {
- for (InetAddress newAddress : target.getDnses()) {
+ for (InetAddress newAddress : target.getDnsServers()) {
if (! result.removed.remove(newAddress)) {
result.added.add(newAddress);
}
@@ -831,7 +875,7 @@
addressCount = in.readInt();
for (int i=0; i<addressCount; i++) {
try {
- netProp.addDns(InetAddress.getByAddress(in.createByteArray()));
+ netProp.addDnsServer(InetAddress.getByAddress(in.createByteArray()));
} catch (UnknownHostException e) { }
}
netProp.setDomains(in.readString());
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 64516e6..318aabe 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -29,10 +29,12 @@
/**
* Identifies a {@code Network}. This is supplied to applications via
- * {@link ConnectivityManager.NetworkCallbackListener} in response to
- * {@link ConnectivityManager#requestNetwork} or {@link ConnectivityManager#listenForNetwork}.
+ * {@link ConnectivityManager.NetworkCallback} in response to the active
+ * {@link ConnectivityManager#requestNetwork} or passive
+ * {@link ConnectivityManager#registerNetworkCallback} calls.
* It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis
- * through a targeted {@link SocketFactory} or process-wide via {@link #bindProcess}.
+ * through a targeted {@link SocketFactory} or process-wide via
+ * {@link ConnectivityManager#setProcessDefaultNetwork}.
*/
public class Network implements Parcelable {
@@ -160,63 +162,13 @@
* @return a {@link SocketFactory} which produces {@link Socket} instances bound to this
* {@code Network}.
*/
- public SocketFactory socketFactory() {
+ public SocketFactory getSocketFactory() {
if (mNetworkBoundSocketFactory == null) {
mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId);
}
return mNetworkBoundSocketFactory;
}
- /**
- * Binds the current process to this network. All sockets created in the future (and not
- * explicitly bound via a bound {@link SocketFactory} (see {@link Network#socketFactory})
- * will be bound to this network. Note that if this {@code Network} ever disconnects
- * all sockets created in this way will cease to work. This is by design so an application
- * doesn't accidentally use sockets it thinks are still bound to a particular {@code Network}.
- */
- public void bindProcess() {
- NetworkUtils.bindProcessToNetwork(netId);
- }
-
- /**
- * Binds host resolutions performed by this process to this network. {@link #bindProcess}
- * takes precedence over this setting.
- *
- * @hide
- * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
- */
- public void bindProcessForHostResolution() {
- NetworkUtils.bindProcessToNetworkForHostResolution(netId);
- }
-
- /**
- * Clears any process specific {@link Network} binding for host resolution. This does
- * not clear bindings enacted via {@link #bindProcess}.
- *
- * @hide
- * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
- */
- public void unbindProcessForHostResolution() {
- NetworkUtils.unbindProcessToNetworkForHostResolution();
- }
-
- /**
- * A static utility method to return any {@code Network} currently bound by this process.
- *
- * @return {@code Network} to which this process is bound.
- */
- public static Network getProcessBoundNetwork() {
- return new Network(NetworkUtils.getNetworkBoundToProcess());
- }
-
- /**
- * Clear any process specific {@code Network} binding. This reverts a call to
- * {@link Network#bindProcess}.
- */
- public static void unbindProcess() {
- NetworkUtils.unbindProcessToNetwork();
- }
-
// implement the Parcelable interface
public int describeContents() {
return 0;
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 7e8b1f1..3d0874b 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -80,6 +80,11 @@
*/
public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3;
+ /* centralize place where base network score, and network score scaling, will be
+ * stored, so as we can consistently compare apple and oranges, or wifi, ethernet and LTE
+ */
+ public static final int WIFI_BASE_SCORE = 60;
+
/**
* Sent by the NetworkAgent to ConnectivityService to pass the current
* network score.
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 35274f1..fe96287 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -44,6 +44,9 @@
private static final String TAG = "NetworkCapabilities";
private static final boolean DBG = false;
+ /**
+ * @hide
+ */
public NetworkCapabilities() {
}
@@ -154,58 +157,64 @@
* Multiple capabilities may be applied sequentially. Note that when searching
* for a network to satisfy a request, all capabilities requested must be satisfied.
*
- * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added.
+ * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added.
+ * @return This NetworkCapability to facilitate chaining.
+ * @hide
*/
- public void addNetworkCapability(int networkCapability) {
- if (networkCapability < MIN_NET_CAPABILITY ||
- networkCapability > MAX_NET_CAPABILITY) {
+ public NetworkCapabilities addCapability(int capability) {
+ if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
throw new IllegalArgumentException("NetworkCapability out of range");
}
- mNetworkCapabilities |= 1 << networkCapability;
+ mNetworkCapabilities |= 1 << capability;
+ return this;
}
/**
* Removes (if found) the given capability from this {@code NetworkCapability} instance.
*
- * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed.
+ * @param capability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed.
+ * @return This NetworkCapability to facilitate chaining.
+ * @hide
*/
- public void removeNetworkCapability(int networkCapability) {
- if (networkCapability < MIN_NET_CAPABILITY ||
- networkCapability > MAX_NET_CAPABILITY) {
+ public NetworkCapabilities removeCapability(int capability) {
+ if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
throw new IllegalArgumentException("NetworkCapability out of range");
}
- mNetworkCapabilities &= ~(1 << networkCapability);
+ mNetworkCapabilities &= ~(1 << capability);
+ return this;
}
/**
* Gets all the capabilities set on this {@code NetworkCapability} instance.
*
- * @return a {@link Collection} of {@code NetworkCapabilities.NET_CAPABILITY_*} values
+ * @return an array of {@code NetworkCapabilities.NET_CAPABILITY_*} values
* for this instance.
+ * @hide
*/
- public Collection<Integer> getNetworkCapabilities() {
+ public int[] getCapabilities() {
return enumerateBits(mNetworkCapabilities);
}
/**
* Tests for the presence of a capabilitity on this instance.
*
- * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for.
+ * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for.
* @return {@code true} if set on this instance.
*/
- public boolean hasCapability(int networkCapability) {
- if (networkCapability < MIN_NET_CAPABILITY ||
- networkCapability > MAX_NET_CAPABILITY) {
+ public boolean hasCapability(int capability) {
+ if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
return false;
}
- return ((mNetworkCapabilities & (1 << networkCapability)) != 0);
+ return ((mNetworkCapabilities & (1 << capability)) != 0);
}
- private Collection<Integer> enumerateBits(long val) {
- ArrayList<Integer> result = new ArrayList<Integer>();
+ private int[] enumerateBits(long val) {
+ int size = Long.bitCount(val);
+ int[] result = new int[size];
+ int index = 0;
int resource = 0;
while (val > 0) {
- if ((val & 1) == 1) result.add(resource);
+ if ((val & 1) == 1) result[index++] = resource;
val = val >> 1;
resource++;
}
@@ -265,33 +274,40 @@
* {@code NetworkCapabilities.NET_CAPABILITY_*} listed above.
*
* @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be added.
+ * @return This NetworkCapability to facilitate chaining.
+ * @hide
*/
- public void addTransportType(int transportType) {
+ public NetworkCapabilities addTransportType(int transportType) {
if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
throw new IllegalArgumentException("TransportType out of range");
}
mTransportTypes |= 1 << transportType;
+ return this;
}
/**
* Removes (if found) the given transport from this {@code NetworkCapability} instance.
*
* @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be removed.
+ * @return This NetworkCapability to facilitate chaining.
+ * @hide
*/
- public void removeTransportType(int transportType) {
+ public NetworkCapabilities removeTransportType(int transportType) {
if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
throw new IllegalArgumentException("TransportType out of range");
}
mTransportTypes &= ~(1 << transportType);
+ return this;
}
/**
* Gets all the transports set on this {@code NetworkCapability} instance.
*
- * @return a {@link Collection} of {@code NetworkCapabilities.TRANSPORT_*} values
+ * @return an array of {@code NetworkCapabilities.TRANSPORT_*} values
* for this instance.
+ * @hide
*/
- public Collection<Integer> getTransportTypes() {
+ public int[] getTransportTypes() {
return enumerateBits(mTransportTypes);
}
@@ -340,6 +356,7 @@
* fast backhauls and slow backhauls.
*
* @param upKbps the estimated first hop upstream (device to network) bandwidth.
+ * @hide
*/
public void setLinkUpstreamBandwidthKbps(int upKbps) {
mLinkUpBandwidthKbps = upKbps;
@@ -368,6 +385,7 @@
* fast backhauls and slow backhauls.
*
* @param downKbps the estimated first hop downstream (network to device) bandwidth.
+ * @hide
*/
public void setLinkDownstreamBandwidthKbps(int downKbps) {
mLinkDownBandwidthKbps = downKbps;
@@ -464,24 +482,22 @@
};
public String toString() {
- Collection<Integer> types = getTransportTypes();
- String transports = (types.size() > 0 ? " Transports: " : "");
- Iterator<Integer> i = types.iterator();
- while (i.hasNext()) {
- switch (i.next()) {
+ int[] types = getTransportTypes();
+ String transports = (types.length > 0 ? " Transports: " : "");
+ for (int i = 0; i < types.length;) {
+ switch (types[i]) {
case TRANSPORT_CELLULAR: transports += "CELLULAR"; break;
case TRANSPORT_WIFI: transports += "WIFI"; break;
case TRANSPORT_BLUETOOTH: transports += "BLUETOOTH"; break;
case TRANSPORT_ETHERNET: transports += "ETHERNET"; break;
}
- if (i.hasNext()) transports += "|";
+ if (++i < types.length) transports += "|";
}
- types = getNetworkCapabilities();
- String capabilities = (types.size() > 0 ? " Capabilities: " : "");
- i = types.iterator();
- while (i.hasNext()) {
- switch (i.next().intValue()) {
+ types = getCapabilities();
+ String capabilities = (types.length > 0 ? " Capabilities: " : "");
+ for (int i = 0; i < types.length; ) {
+ switch (types[i]) {
case NET_CAPABILITY_MMS: capabilities += "MMS"; break;
case NET_CAPABILITY_SUPL: capabilities += "SUPL"; break;
case NET_CAPABILITY_DUN: capabilities += "DUN"; break;
@@ -497,7 +513,7 @@
case NET_CAPABILITY_INTERNET: capabilities += "INTERNET"; break;
case NET_CAPABILITY_NOT_RESTRICTED: capabilities += "NOT_RESTRICTED"; break;
}
- if (i.hasNext()) capabilities += "&";
+ if (++i < types.length) capabilities += "&";
}
String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" +
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 47377e9..36dc573 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -22,19 +22,14 @@
import java.util.concurrent.atomic.AtomicInteger;
/**
- * Defines a request for a network, made by calling {@link ConnectivityManager#requestNetwork}
- * or {@link ConnectivityManager#listenForNetwork}.
- *
- * This token records the {@link NetworkCapabilities} used to make the request and identifies
- * the request. It should be used to release the request via
- * {@link ConnectivityManager#releaseNetworkRequest} when the network is no longer desired.
+ * Defines a request for a network, made through {@link NetworkRequest.Builder} and used
+ * to request a network via {@link ConnectivityManager#requestNetwork} or listen for changes
+ * via {@link ConnectivityManager#registerNetworkCallback}.
*/
public class NetworkRequest implements Parcelable {
/**
- * The {@link NetworkCapabilities} that define this request. This should not be modified.
- * The networkCapabilities of the request are set when
- * {@link ConnectivityManager#requestNetwork} is called and the value is presented here
- * as a convenient reminder of what was requested.
+ * The {@link NetworkCapabilities} that define this request.
+ * @hide
*/
public final NetworkCapabilities networkCapabilities;
@@ -71,6 +66,95 @@
this.legacyType = that.legacyType;
}
+ /**
+ * Builder used to create {@link NetworkRequest} objects. Specify the Network features
+ * needed in terms of {@link NetworkCapabilities} features
+ */
+ public static class Builder {
+ private final NetworkCapabilities mNetworkCapabilities = new NetworkCapabilities();
+
+ /**
+ * Default constructor for Builder.
+ */
+ public Builder() {}
+
+ /**
+ * Build {@link NetworkRequest} give the current set of capabilities.
+ */
+ public NetworkRequest build() {
+ return new NetworkRequest(mNetworkCapabilities, ConnectivityManager.TYPE_NONE,
+ ConnectivityManager.REQUEST_ID_UNSET);
+ }
+
+ /**
+ * Add the given capability requirement to this builder. These represent
+ * the requested network's required capabilities. Note that when searching
+ * for a network to satisfy a request, all capabilities requested must be
+ * satisfied. See {@link NetworkCapabilities} for {@code NET_CAPABILITIY_*}
+ * definitions.
+ *
+ * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to add.
+ * @return The builder to facilitate chaining
+ * {@code builder.addCapability(...).addCapability();}.
+ */
+ public Builder addCapability(int capability) {
+ mNetworkCapabilities.addCapability(capability);
+ return this;
+ }
+
+ /**
+ * Removes (if found) the given capability from this builder instance.
+ *
+ * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to remove.
+ * @return The builder to facilitate chaining.
+ */
+ public Builder removeCapability(int capability) {
+ mNetworkCapabilities.removeCapability(capability);
+ return this;
+ }
+
+ /**
+ * Adds the given transport requirement to this builder. These represent
+ * the set of allowed transports for the request. Only networks using one
+ * of these transports will satisfy the request. If no particular transports
+ * are required, none should be specified here. See {@link NetworkCapabilities}
+ * for {@code TRANSPORT_*} definitions.
+ *
+ * @param transportType The {@code NetworkCapabilities.TRANSPORT_*} to add.
+ * @return The builder to facilitate chaining.
+ */
+ public Builder addTransportType(int transportType) {
+ mNetworkCapabilities.addTransportType(transportType);
+ return this;
+ }
+
+ /**
+ * Removes (if found) the given transport from this builder instance.
+ *
+ * @param transportType The {@code NetworkCapabilities.TRANSPORT_*} to remove.
+ * @return The builder to facilitate chaining.
+ */
+ public Builder removeTransportType(int transportType) {
+ mNetworkCapabilities.removeTransportType(transportType);
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ public Builder setLinkUpstreamBandwidthKbps(int upKbps) {
+ mNetworkCapabilities.setLinkUpstreamBandwidthKbps(upKbps);
+ return this;
+ }
+ /**
+ * @hide
+ */
+ public Builder setLinkDownstreamBandwidthKbps(int downKbps) {
+ mNetworkCapabilities.setLinkDownstreamBandwidthKbps(downKbps);
+ return this;
+ }
+ }
+
// implement the Parcelable interface
public int describeContents() {
return 0;
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index edb3286..15c0a71 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -24,6 +24,8 @@
import java.util.Locale;
import android.util.Log;
+import android.util.Pair;
+
/**
* Native methods for managing network interfaces.
@@ -111,7 +113,7 @@
/**
* Binds the current process to the network designated by {@code netId}. All sockets created
* in the future (and not explicitly bound via a bound {@link SocketFactory} (see
- * {@link Network#socketFactory}) will be bound to this network. Note that if this
+ * {@link Network#getSocketFactory}) will be bound to this network. Note that if this
* {@code Network} ever disconnects all sockets created in this way will cease to work. This
* is by design so an application doesn't accidentally use sockets it thinks are still bound to
* a particular {@code Network}.
@@ -218,24 +220,17 @@
}
/**
- * Get InetAddress masked with prefixLength. Will never return null.
- * @param IP address which will be masked with specified prefixLength
- * @param prefixLength the prefixLength used to mask the IP
+ * Masks a raw IP address byte array with the specified prefix length.
*/
- public static InetAddress getNetworkPart(InetAddress address, int prefixLength) {
- if (address == null) {
- throw new RuntimeException("getNetworkPart doesn't accept null address");
- }
-
- byte[] array = address.getAddress();
-
+ public static void maskRawAddress(byte[] array, int prefixLength) {
if (prefixLength < 0 || prefixLength > array.length * 8) {
- throw new RuntimeException("getNetworkPart - bad prefixLength");
+ throw new RuntimeException("IP address with " + array.length +
+ " bytes has invalid prefix length " + prefixLength);
}
int offset = prefixLength / 8;
- int reminder = prefixLength % 8;
- byte mask = (byte)(0xFF << (8 - reminder));
+ int remainder = prefixLength % 8;
+ byte mask = (byte)(0xFF << (8 - remainder));
if (offset < array.length) array[offset] = (byte)(array[offset] & mask);
@@ -244,6 +239,16 @@
for (; offset < array.length; offset++) {
array[offset] = 0;
}
+ }
+
+ /**
+ * Get InetAddress masked with prefixLength. Will never return null.
+ * @param address the IP address to mask with
+ * @param prefixLength the prefixLength used to mask the IP
+ */
+ public static InetAddress getNetworkPart(InetAddress address, int prefixLength) {
+ byte[] array = address.getAddress();
+ maskRawAddress(array, prefixLength);
InetAddress netPart = null;
try {
@@ -255,6 +260,30 @@
}
/**
+ * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64".
+ * @hide
+ */
+ public static Pair<InetAddress, Integer> parseIpAndMask(String ipAndMaskString) {
+ InetAddress address = null;
+ int prefixLength = -1;
+ try {
+ String[] pieces = ipAndMaskString.split("/", 2);
+ prefixLength = Integer.parseInt(pieces[1]);
+ address = InetAddress.parseNumericAddress(pieces[0]);
+ } catch (NullPointerException e) { // Null string.
+ } catch (ArrayIndexOutOfBoundsException e) { // No prefix length.
+ } catch (NumberFormatException e) { // Non-numeric prefix.
+ } catch (IllegalArgumentException e) { // Invalid IP address.
+ }
+
+ if (address == null || prefixLength == -1) {
+ throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString);
+ }
+
+ return new Pair<InetAddress, Integer>(address, prefixLength);
+ }
+
+ /**
* Check if IP address type is consistent between two InetAddress.
* @return true if both are the same type. False otherwise.
*/
diff --git a/core/java/android/net/PSKKeyManager.java b/core/java/android/net/PSKKeyManager.java
new file mode 100644
index 0000000..92dd141
--- /dev/null
+++ b/core/java/android/net/PSKKeyManager.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import java.net.Socket;
+import javax.crypto.SecretKey;
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Provider of key material for pre-shared key (PSK) key exchange used in TLS-PSK cipher suites.
+ *
+ * <h3>Overview of TLS-PSK</h3>
+ *
+ * <p>TLS-PSK is a set of TLS/SSL cipher suites which rely on a symmetric pre-shared key (PSK) to
+ * secure the TLS/SSL connection and mutually authenticate its peers. These cipher suites may be
+ * a more natural fit compared to conventional public key based cipher suites in some scenarios
+ * where communication between peers is bootstrapped via a separate step (for example, a pairing
+ * step) and requires both peers to authenticate each other. In such scenarios a symmetric key (PSK)
+ * can be exchanged during the bootstrapping step, removing the need to generate and exchange public
+ * key pairs and X.509 certificates.</p>
+ *
+ * <p>When a TLS-PSK cipher suite is used, both peers have to use the same key for the TLS/SSL
+ * handshake to succeed. Thus, both peers are implicitly authenticated by a successful handshake.
+ * This removes the need to use a {@code TrustManager} in conjunction with this {@code KeyManager}.
+ * </p>
+ *
+ * <h3>Supporting multiple keys</h3>
+ *
+ * <p>A peer may have multiple keys to choose from. To help choose the right key, during the handshake
+ * the server can provide a <em>PSK identity hint</em> to the client, and the client can provide a
+ * <em>PSK identity</em> to the server. The contents of these two pieces of information are specific
+ * to application-level protocols.</p>
+ *
+ * <p><em>NOTE: Both the PSK identity hint and the PSK identity are transmitted in cleartext.
+ * Moreover, these data are received and processed prior to peer having been authenticated. Thus,
+ * they must not contain or leak key material or other sensitive information, and should be
+ * treated (e.g., parsed) with caution, as untrusted data.</em></p>
+ *
+ * <p>The high-level flow leading to peers choosing a key during TLS/SSL handshake is as follows:
+ * <ol>
+ * <li>Server receives a handshake request from client.
+ * <li>Server replies, optionally providing a PSK identity hint to client.</li>
+ * <li>Client chooses the key.</li>
+ * <li>Client provides a PSK identity of the chosen key to server.</li>
+ * <li>Server chooses the key.</li>
+ * </ol></p>
+ *
+ * <p>In the flow above, either peer can signal that they do not have a suitable key, in which case
+ * the the handshake will be aborted immediately. This may enable a network attacker who does not
+ * know the key to learn which PSK identity hints or PSK identities are supported. If this is a
+ * concern then a randomly generated key should be used in the scenario where no key is available.
+ * This will lead to the handshake aborting later, due to key mismatch -- same as in the scenario
+ * where a key is available -- making it appear to the attacker that all PSK identity hints and PSK
+ * identities are supported.</p>
+ *
+ * <h3>Maximum sizes</h3>
+ *
+ * <p>The maximum supported sizes are as follows:
+ * <ul>
+ * <li>256 bytes for keys (see {@link #MAX_KEY_LENGTH_BYTES}),</li>
+ * <li>128 bytes for PSK identity and PSK identity hint (in modified UTF-8 representation) (see
+ * {@link #MAX_IDENTITY_LENGTH_BYTES} and {@link #MAX_IDENTITY_HINT_LENGTH_BYTES}).</li>
+ * </ul></p>
+ *
+ * <h3>Example</h3>
+ * The following example illustrates how to create an {@code SSLContext} which enables the use of
+ * TLS-PSK in {@code SSLSocket}, {@code SSLServerSocket} and {@code SSLEngine} instances obtained
+ * from it.
+ * <pre> {@code
+ * PSKKeyManager myPskKeyManager = ...;
+ *
+ * SSLContext sslContext = SSLContext.getInstance("TLS");
+ * sslContext.init(
+ * new KeyManager[] {myPskKeyManager},
+ * new TrustManager[0], // No TrustManagers needed in TLS-PSK
+ * null // Use the default source of entropy
+ * );
+ *
+ * SSLSocket sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(...);
+ * // Enable a TLS-PSK cipher suite (no TLS-PSK cipher suites are enabled by default)
+ * sslSocket.setEnabledCipherSuites(new String[] {"TLS_PSK_WITH_AES_128_CBC_SHA"});
+ * sslSocket.startHandshake();
+ * }</pre>
+ */
+public interface PSKKeyManager extends com.android.org.conscrypt.PSKKeyManager {
+ // IMPLEMENTATION DETAILS: This class exists only because the default implemenetation of the
+ // TLS/SSL JSSE provider (currently Conscrypt) cannot depend on Android framework classes.
+ // As a result, this framework class simply extends the PSKKeyManager interface from Conscrypt
+ // without adding any new methods or fields. Moreover, for technical reasons (Conscrypt classes
+ // are "hidden") this class replaces the Javadoc of Conscrypt's PSKKeyManager.
+
+ /**
+ * Maximum supported length (in bytes) for PSK identity hint (in modified UTF-8 representation).
+ */
+ int MAX_IDENTITY_HINT_LENGTH_BYTES =
+ com.android.org.conscrypt.PSKKeyManager.MAX_IDENTITY_HINT_LENGTH_BYTES;
+
+ /** Maximum supported length (in bytes) for PSK identity (in modified UTF-8 representation). */
+ int MAX_IDENTITY_LENGTH_BYTES =
+ com.android.org.conscrypt.PSKKeyManager.MAX_IDENTITY_LENGTH_BYTES;
+
+ /** Maximum supported length (in bytes) for PSK. */
+ int MAX_KEY_LENGTH_BYTES = com.android.org.conscrypt.PSKKeyManager.MAX_KEY_LENGTH_BYTES;
+
+ /**
+ * Gets the PSK identity hint to report to the client to help agree on the PSK for the provided
+ * socket.
+ *
+ * @return PSK identity hint to be provided to the client or {@code null} to provide no hint.
+ */
+ @Override
+ String chooseServerKeyIdentityHint(Socket socket);
+
+ /**
+ * Gets the PSK identity hint to report to the client to help agree on the PSK for the provided
+ * engine.
+ *
+ * @return PSK identity hint to be provided to the client or {@code null} to provide no hint.
+ */
+ @Override
+ String chooseServerKeyIdentityHint(SSLEngine engine);
+
+ /**
+ * Gets the PSK identity to report to the server to help agree on the PSK for the provided
+ * socket.
+ *
+ * @param identityHint identity hint provided by the server or {@code null} if none provided.
+ *
+ * @return PSK identity to provide to the server. {@code null} is permitted but will be
+ * converted into an empty string.
+ */
+ @Override
+ String chooseClientKeyIdentity(String identityHint, Socket socket);
+
+ /**
+ * Gets the PSK identity to report to the server to help agree on the PSK for the provided
+ * engine.
+ *
+ * @param identityHint identity hint provided by the server or {@code null} if none provided.
+ *
+ * @return PSK identity to provide to the server. {@code null} is permitted but will be
+ * converted into an empty string.
+ */
+ @Override
+ String chooseClientKeyIdentity(String identityHint, SSLEngine engine);
+
+ /**
+ * Gets the PSK to use for the provided socket.
+ *
+ * @param identityHint identity hint provided by the server to help select the key or
+ * {@code null} if none provided.
+ * @param identity identity provided by the client to help select the key.
+ *
+ * @return key or {@code null} to signal to peer that no suitable key is available and to abort
+ * the handshake.
+ */
+ @Override
+ SecretKey getKey(String identityHint, String identity, Socket socket);
+
+ /**
+ * Gets the PSK to use for the provided engine.
+ *
+ * @param identityHint identity hint provided by the server to help select the key or
+ * {@code null} if none provided.
+ * @param identity identity provided by the client to help select the key.
+ *
+ * @return key or {@code null} to signal to peer that no suitable key is available and to abort
+ * the handshake.
+ */
+ @Override
+ SecretKey getKey(String identityHint, String identity, SSLEngine engine);
+}
diff --git a/core/java/android/net/ProxyDataTracker.java b/core/java/android/net/ProxyDataTracker.java
index 0340e7e..a578383 100644
--- a/core/java/android/net/ProxyDataTracker.java
+++ b/core/java/android/net/ProxyDataTracker.java
@@ -108,8 +108,8 @@
mNetworkCapabilities = new NetworkCapabilities();
mNetworkInfo.setIsAvailable(true);
try {
- mLinkProperties.addDns(InetAddress.getByName(DNS1));
- mLinkProperties.addDns(InetAddress.getByName(DNS2));
+ mLinkProperties.addDnsServer(InetAddress.getByName(DNS1));
+ mLinkProperties.addDnsServer(InetAddress.getByName(DNS2));
mLinkProperties.setInterfaceName(INTERFACE_NAME);
} catch (UnknownHostException e) {
Log.e(TAG, "Could not add DNS address", e);
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index ad8e4f7..63d6cd3 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -35,10 +35,10 @@
*
* A route contains three pieces of information:
* <ul>
- * <li>a destination {@link LinkAddress} for directly-connected subnets. If this is
- * {@code null} it indicates a default route of the address family (IPv4 or IPv6)
+ * <li>a destination {@link IpPrefix} specifying the network destinations covered by this route.
+ * If this is {@code null} it indicates a default route of the address family (IPv4 or IPv6)
* implied by the gateway IP address.
- * <li>a gateway {@link InetAddress} for default routes. If this is {@code null} it
+ * <li>a gateway {@link InetAddress} indicating the next hop to use. If this is {@code null} it
* indicates a directly-connected route.
* <li>an interface (which may be unspecified).
* </ul>
@@ -46,9 +46,10 @@
* destination and gateway are both specified, they must be of the same address family
* (IPv4 or IPv6).
*/
-public class RouteInfo implements Parcelable {
+public final class RouteInfo implements Parcelable {
/**
* The IP destination address for this route.
+ * TODO: Make this an IpPrefix.
*/
private final LinkAddress mDestination;
@@ -80,6 +81,19 @@
* @param destination the destination prefix
* @param gateway the IP address to route packets through
* @param iface the interface name to send packets on
+ *
+ * TODO: Convert to use IpPrefix.
+ *
+ * @hide
+ */
+ public RouteInfo(IpPrefix destination, InetAddress gateway, String iface) {
+ this(destination == null ? null :
+ new LinkAddress(destination.getAddress(), destination.getPrefixLength()),
+ gateway, iface);
+ }
+
+ /**
+ * @hide
*/
public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
if (destination == null) {
@@ -105,7 +119,7 @@
mHasGateway = (!gateway.isAnyLocalAddress());
mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(),
- destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
+ destination.getPrefixLength()), destination.getPrefixLength());
if ((destination.getAddress() instanceof Inet4Address &&
(gateway instanceof Inet4Address == false)) ||
(destination.getAddress() instanceof Inet6Address &&
@@ -128,8 +142,17 @@
* <p>
* Destination and gateway may not both be null.
*
- * @param destination the destination address and prefix in a {@link LinkAddress}
+ * @param destination the destination address and prefix in an {@link IpPrefix}
* @param gateway the {@link InetAddress} to route packets through
+ *
+ * @hide
+ */
+ public RouteInfo(IpPrefix destination, InetAddress gateway) {
+ this(destination, gateway, null);
+ }
+
+ /**
+ * @hide
*/
public RouteInfo(LinkAddress destination, InetAddress gateway) {
this(destination, gateway, null);
@@ -139,16 +162,27 @@
* Constructs a default {@code RouteInfo} object.
*
* @param gateway the {@link InetAddress} to route packets through
+ *
+ * @hide
*/
public RouteInfo(InetAddress gateway) {
- this(null, gateway, null);
+ this((LinkAddress) null, gateway, null);
}
/**
* Constructs a {@code RouteInfo} object representing a direct connected subnet.
*
- * @param destination the {@link LinkAddress} describing the address and prefix
+ * @param destination the {@link IpPrefix} describing the address and prefix
* length of the subnet.
+ *
+ * @hide
+ */
+ public RouteInfo(IpPrefix destination) {
+ this(destination, null, null);
+ }
+
+ /**
+ * @hide
*/
public RouteInfo(LinkAddress destination) {
this(destination, null, null);
@@ -176,29 +210,37 @@
private boolean isHost() {
return (mDestination.getAddress() instanceof Inet4Address &&
- mDestination.getNetworkPrefixLength() == 32) ||
+ mDestination.getPrefixLength() == 32) ||
(mDestination.getAddress() instanceof Inet6Address &&
- mDestination.getNetworkPrefixLength() == 128);
+ mDestination.getPrefixLength() == 128);
}
private boolean isDefault() {
boolean val = false;
if (mGateway != null) {
if (mGateway instanceof Inet4Address) {
- val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0);
+ val = (mDestination == null || mDestination.getPrefixLength() == 0);
} else {
- val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0);
+ val = (mDestination == null || mDestination.getPrefixLength() == 0);
}
}
return val;
}
/**
- * Retrieves the destination address and prefix length in the form of a {@link LinkAddress}.
+ * Retrieves the destination address and prefix length in the form of an {@link IpPrefix}.
*
- * @return {@link LinkAddress} specifying the destination. This is never {@code null}.
+ * @return {@link IpPrefix} specifying the destination. This is never {@code null}.
*/
- public LinkAddress getDestination() {
+ public IpPrefix getDestination() {
+ return new IpPrefix(mDestination.getAddress(), mDestination.getPrefixLength());
+ }
+
+ /**
+ * TODO: Convert callers to use IpPrefix and then remove.
+ * @hide
+ */
+ public LinkAddress getDestinationLinkAddress() {
return mDestination;
}
@@ -206,7 +248,7 @@
* Retrieves the gateway or next hop {@link InetAddress} for this route.
*
* @return {@link InetAddress} specifying the gateway or next hop. This may be
- & {@code null} for a directly-connected route."
+ * {@code null} for a directly-connected route."
*/
public InetAddress getGateway() {
return mGateway;
@@ -233,7 +275,8 @@
/**
* Indicates if this route is a host route (ie, matches only a single host address).
*
- * @return {@code true} if the destination has a prefix length of 32/128 for v4/v6.
+ * @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6,
+ * respectively.
* @hide
*/
public boolean isHostRoute() {
@@ -263,7 +306,7 @@
// match the route destination and destination with prefix length
InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
- mDestination.getNetworkPrefixLength());
+ mDestination.getPrefixLength());
return mDestination.getAddress().equals(dstNet);
}
@@ -285,8 +328,8 @@
for (RouteInfo route : routes) {
if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) {
if ((bestRoute != null) &&
- (bestRoute.mDestination.getNetworkPrefixLength() >=
- route.mDestination.getNetworkPrefixLength())) {
+ (bestRoute.mDestination.getPrefixLength() >=
+ route.mDestination.getPrefixLength())) {
continue;
}
if (route.matches(dest)) bestRoute = route;
@@ -295,13 +338,22 @@
return bestRoute;
}
+ /**
+ * Returns a human-readable description of this object.
+ */
public String toString() {
String val = "";
if (mDestination != null) val = mDestination.toString();
- if (mGateway != null) val += " -> " + mGateway.getHostAddress();
+ val += " ->";
+ if (mGateway != null) val += " " + mGateway.getHostAddress();
+ if (mInterface != null) val += " " + mInterface;
return val;
}
+ /**
+ * Compares this RouteInfo object against the specified object and indicates if they are equal.
+ * @return {@code true} if the objects are equal, {@code false} otherwise.
+ */
public boolean equals(Object obj) {
if (this == obj) return true;
@@ -309,11 +361,14 @@
RouteInfo target = (RouteInfo) obj;
- return Objects.equals(mDestination, target.getDestination()) &&
+ return Objects.equals(mDestination, target.getDestinationLinkAddress()) &&
Objects.equals(mGateway, target.getGateway()) &&
Objects.equals(mInterface, target.getInterface());
}
+ /**
+ * Returns a hashcode for this <code>RouteInfo</code> object.
+ */
public int hashCode() {
return (mDestination == null ? 0 : mDestination.hashCode() * 41)
+ (mGateway == null ? 0 :mGateway.hashCode() * 47)
@@ -323,7 +378,6 @@
/**
* Implement the Parcelable interface
- * @hide
*/
public int describeContents() {
return 0;
@@ -331,7 +385,6 @@
/**
* Implement the Parcelable interface
- * @hide
*/
public void writeToParcel(Parcel dest, int flags) {
if (mDestination == null) {
@@ -339,7 +392,7 @@
} else {
dest.writeByte((byte) 1);
dest.writeByteArray(mDestination.getAddress().getAddress());
- dest.writeInt(mDestination.getNetworkPrefixLength());
+ dest.writeInt(mDestination.getPrefixLength());
}
if (mGateway == null) {
@@ -354,7 +407,6 @@
/**
* Implement the Parcelable interface.
- * @hide
*/
public static final Creator<RouteInfo> CREATOR =
new Creator<RouteInfo>() {
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 32050dc..537e993 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -128,29 +128,97 @@
public static final int BATTERY_PLUGGED_ANY =
BATTERY_PLUGGED_AC | BATTERY_PLUGGED_USB | BATTERY_PLUGGED_WIRELESS;
+ /*
+ * Battery property identifiers. These must match the values in
+ * frameworks/native/include/batteryservice/BatteryService.h
+ */
+ /** Battery capacity in microampere-hours, as an integer. */
+ public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1;
+
+ /**
+ * Instantaneous battery current in microamperes, as an integer. Positive
+ * values indicate net current entering the battery from a charge source,
+ * negative values indicate net current discharging from the battery.
+ */
+ public static final int BATTERY_PROPERTY_CURRENT_NOW = 2;
+
+ /**
+ * Average battery current in microamperes, as an integer. Positive
+ * values indicate net current entering the battery from a charge source,
+ * negative values indicate net current discharging from the battery.
+ * The time period over which the average is computed may depend on the
+ * fuel gauge hardware and its configuration.
+ */
+ public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3;
+
+ /**
+ * Remaining battery capacity as an integer percentage of total capacity
+ * (with no fractional part).
+ */
+ public static final int BATTERY_PROPERTY_CAPACITY = 4;
+
+ /**
+ * Battery remaining energy in nanowatt-hours, as a long integer.
+ */
+ public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5;
+
private IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
/**
- * Return the requested battery property.
+ * Query a battery property from the batteryproperties service.
*
- * @param id identifier from {@link BatteryProperty} of the requested property
- * @return a {@link BatteryProperty} object that returns the property value, or null on error
+ * Returns the requested value, or Long.MIN_VALUE if property not
+ * supported on this system or on other error.
*/
- public BatteryProperty getProperty(int id) throws RemoteException {
+ private long queryProperty(int id) {
+ long ret;
+
if (mBatteryPropertiesRegistrar == null) {
IBinder b = ServiceManager.getService("batteryproperties");
mBatteryPropertiesRegistrar =
IBatteryPropertiesRegistrar.Stub.asInterface(b);
if (mBatteryPropertiesRegistrar == null)
- return null;
+ return Long.MIN_VALUE;
}
- BatteryProperty prop = new BatteryProperty();
- if ((mBatteryPropertiesRegistrar.getProperty(id, prop) == 0) &&
- (prop.getLong() != Long.MIN_VALUE))
- return prop;
- else
- return null;
+ try {
+ BatteryProperty prop = new BatteryProperty();
+
+ if (mBatteryPropertiesRegistrar.getProperty(id, prop) == 0)
+ ret = prop.getLong();
+ else
+ ret = Long.MIN_VALUE;
+ } catch (RemoteException e) {
+ ret = Long.MIN_VALUE;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Return the value of a battery property of integer type. If the
+ * platform does not provide the property queried, this value will
+ * be Integer.MIN_VALUE.
+ *
+ * @param id identifier of the requested property
+ *
+ * @return the property value, or Integer.MIN_VALUE if not supported.
+ */
+ public int getIntProperty(int id) {
+ return (int)queryProperty(id);
+ }
+
+ /**
+ * Return the value of a battery property of long type If the
+ * platform does not provide the property queried, this value will
+ * be Long.MIN_VALUE.
+ *
+ * @param id identifier of the requested property
+ *
+ * @return the property value, or Long.MIN_VALUE if not supported.
+ */
+ public long getLongProperty(int id) {
+ return queryProperty(id);
}
}
diff --git a/core/java/android/os/BatteryProperty.java b/core/java/android/os/BatteryProperty.java
index 27dad4f..84119bd 100644
--- a/core/java/android/os/BatteryProperty.java
+++ b/core/java/android/os/BatteryProperty.java
@@ -20,44 +20,13 @@
/**
* Battery properties that may be queried using
- * {@link BatteryManager#getProperty
* BatteryManager.getProperty()}
*/
+
+/**
+ * @hide
+ */
public class BatteryProperty implements Parcelable {
- /*
- * Battery property identifiers. These must match the values in
- * frameworks/native/include/batteryservice/BatteryService.h
- */
- /** Battery capacity in microampere-hours, as an integer. */
- public static final int CHARGE_COUNTER = 1;
-
- /**
- * Instantaneous battery current in microamperes, as an integer. Positive
- * values indicate net current entering the battery from a charge source,
- * negative values indicate net current discharging from the battery.
- */
- public static final int CURRENT_NOW = 2;
-
- /**
- * Average battery current in microamperes, as an integer. Positive
- * values indicate net current entering the battery from a charge source,
- * negative values indicate net current discharging from the battery.
- * The time period over which the average is computed may depend on the
- * fuel gauge hardware and its configuration.
- */
- public static final int CURRENT_AVERAGE = 3;
-
- /**
- * Remaining battery capacity as an integer percentage of total capacity
- * (with no fractional part).
- */
- public static final int CAPACITY = 4;
-
- /**
- * Battery remaining energy in nanowatt-hours, as a long integer.
- */
- public static final int ENERGY_COUNTER = 5;
-
private long mValueLong;
/**
@@ -68,30 +37,12 @@
}
/**
- * Return the value of a property of integer type previously queried
- * via {@link BatteryManager#getProperty
- * BatteryManager.getProperty()}. If the platform does
- * not provide the property queried, this value will be
- * Integer.MIN_VALUE.
- *
- * @return The queried property value, or Integer.MIN_VALUE if not supported.
- */
- public int getInt() {
- return (int)mValueLong;
- }
-
- /**
- * Return the value of a property of long type previously queried
- * via {@link BatteryManager#getProperty
- * BatteryManager.getProperty()}. If the platform does
- * not provide the property queried, this value will be
- * Long.MIN_VALUE.
- *
- * @return The queried property value, or Long.MIN_VALUE if not supported.
+ * @hide
*/
public long getLong() {
return mValueLong;
}
+
/*
* Parcel read/write code must be kept in sync with
* frameworks/native/services/batteryservice/BatteryProperty.cpp
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index cd47099..e77ef95 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -39,9 +39,6 @@
UserInfo getProfileParent(int userHandle);
UserInfo getUserInfo(int userHandle);
boolean isRestricted();
- void setGuestEnabled(boolean enable);
- boolean isGuestEnabled();
- void wipeUser(int userHandle);
int getUserSerialNumber(int userHandle);
int getUserHandle(int userSerialNumber);
Bundle getUserRestrictions(int userHandle);
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 914c170..afbf983 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -16,7 +16,10 @@
package android.os;
+import android.util.SparseArray;
+
import java.io.PrintWriter;
+import java.util.HashMap;
/**
* Representation of a user on the device.
@@ -66,6 +69,8 @@
final int mHandle;
+ private static final SparseArray<UserHandle> userHandles = new SparseArray<UserHandle>();
+
/**
* Checks to see if the user id is the same for the two uids, i.e., they belong to the same
* user.
@@ -124,6 +129,18 @@
return getUserId(Binder.getCallingUid());
}
+ /** @hide */
+ public static final UserHandle getCallingUserHandle() {
+ int userId = getUserId(Binder.getCallingUid());
+ UserHandle userHandle = userHandles.get(userId);
+ // Intentionally not synchronized to save time
+ if (userHandle == null) {
+ userHandle = new UserHandle(userId);
+ userHandles.put(userId, userHandle);
+ }
+ return userHandle;
+ }
+
/**
* Returns the uid that is composed from the userId and the appId.
* @hide
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f7a89ba..468cfe0 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -25,6 +25,7 @@
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.provider.Settings;
import android.util.Log;
import com.android.internal.R;
@@ -361,6 +362,16 @@
}
/**
+ * Checks if the calling app is running as a guest user.
+ * @return whether the caller is a guest user.
+ * @hide
+ */
+ public boolean isGuestUser() {
+ UserInfo user = getUserInfo(UserHandle.myUserId());
+ return user != null ? user.isGuest() : false;
+ }
+
+ /**
* Return whether the given user is actively running. This means that
* the user is in the "started" state, not "stopped" -- it is currently
* allowed to run code through scheduled alarms, receiving broadcasts,
@@ -481,10 +492,11 @@
}
/**
- * @hide
* Returns whether the current user has been disallowed from performing certain actions
* or setting certain settings.
- * @param restrictionKey the string key representing the restriction
+ *
+ * @param restrictionKey The string key representing the restriction.
+ * @return {@code true} if the current user has the given restriction, {@code false} otherwise.
*/
public boolean hasUserRestriction(String restrictionKey) {
return hasUserRestriction(restrictionKey, Process.myUserHandle());
@@ -549,6 +561,21 @@
}
/**
+ * Creates a guest user and configures it.
+ * @param context an application context
+ * @param name the name to set for the user
+ * @hide
+ */
+ public UserInfo createGuest(Context context, String name) {
+ UserInfo guest = createUser(name, UserInfo.FLAG_GUEST);
+ if (guest != null) {
+ Settings.Secure.putStringForUser(context.getContentResolver(),
+ Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
+ }
+ return guest;
+ }
+
+ /**
* Creates a user with the specified name and options as a profile of another user.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
*
@@ -826,50 +853,6 @@
}
/**
- * Enable or disable the use of a guest account. If disabled, the existing guest account
- * will be wiped.
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
- * @param enable whether to enable a guest account.
- * @hide
- */
- public void setGuestEnabled(boolean enable) {
- try {
- mService.setGuestEnabled(enable);
- } catch (RemoteException re) {
- Log.w(TAG, "Could not change guest account availability to " + enable);
- }
- }
-
- /**
- * Checks if a guest user is enabled for this device.
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
- * @return whether a guest user is enabled
- * @hide
- */
- public boolean isGuestEnabled() {
- try {
- return mService.isGuestEnabled();
- } catch (RemoteException re) {
- Log.w(TAG, "Could not retrieve guest enabled state");
- return false;
- }
- }
-
- /**
- * Wipes all the data for a user, but doesn't remove the user.
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
- * @param userHandle
- * @hide
- */
- public void wipeUser(int userHandle) {
- try {
- mService.wipeUser(userHandle);
- } catch (RemoteException re) {
- Log.w(TAG, "Could not wipe user " + userHandle);
- }
- }
-
- /**
* Returns the maximum number of users that can be created on this device. A return value
* of 1 means that it is a single user device.
* @hide
@@ -899,7 +882,9 @@
++switchableUserCount;
}
}
- return switchableUserCount > 1;
+ final boolean guestEnabled = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.GUEST_USER_ENABLED, 0) == 1;
+ return switchableUserCount > 1 || guestEnabled;
}
/**
diff --git a/core/java/android/preference/SeekBarPreference.java b/core/java/android/preference/SeekBarPreference.java
index e32890d..67f6409 100644
--- a/core/java/android/preference/SeekBarPreference.java
+++ b/core/java/android/preference/SeekBarPreference.java
@@ -40,11 +40,19 @@
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- final TypedArray a = context.obtainStyledAttributes(
+ TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.ProgressBar, defStyleAttr, defStyleRes);
setMax(a.getInt(com.android.internal.R.styleable.ProgressBar_max, mMax));
a.recycle();
- setLayoutResource(com.android.internal.R.layout.preference_widget_seekbar);
+
+ a = context.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.SeekBarPreference, defStyleAttr, defStyleRes);
+ final int layoutResId = a.getResourceId(
+ com.android.internal.R.styleable.SeekBarPreference_layout,
+ com.android.internal.R.layout.preference_widget_seekbar);
+ a.recycle();
+
+ setLayoutResource(layoutResId);
}
public SeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -52,7 +60,7 @@
}
public SeekBarPreference(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
+ this(context, attrs, com.android.internal.R.attr.seekBarPreferenceStyle);
}
public SeekBarPreference(Context context) {
diff --git a/core/java/android/print/ILayoutResultCallback.aidl b/core/java/android/print/ILayoutResultCallback.aidl
index 43b8c30..68c1dac 100644
--- a/core/java/android/print/ILayoutResultCallback.aidl
+++ b/core/java/android/print/ILayoutResultCallback.aidl
@@ -16,6 +16,7 @@
package android.print;
+import android.os.ICancellationSignal;
import android.print.PrintDocumentInfo;
/**
@@ -24,6 +25,8 @@
* @hide
*/
oneway interface ILayoutResultCallback {
+ void onLayoutStarted(ICancellationSignal cancellation, int sequence);
void onLayoutFinished(in PrintDocumentInfo info, boolean changed, int sequence);
void onLayoutFailed(CharSequence error, int sequence);
+ void onLayoutCanceled(int sequence);
}
diff --git a/core/java/android/print/IPrintDocumentAdapter.aidl b/core/java/android/print/IPrintDocumentAdapter.aidl
index 2b95c12..9d384fb 100644
--- a/core/java/android/print/IPrintDocumentAdapter.aidl
+++ b/core/java/android/print/IPrintDocumentAdapter.aidl
@@ -37,5 +37,4 @@
void write(in PageRange[] pages, in ParcelFileDescriptor fd,
IWriteResultCallback callback, int sequence);
void finish();
- void cancel();
}
diff --git a/core/java/android/print/IWriteResultCallback.aidl b/core/java/android/print/IWriteResultCallback.aidl
index 8281c4e..8fb33e1 100644
--- a/core/java/android/print/IWriteResultCallback.aidl
+++ b/core/java/android/print/IWriteResultCallback.aidl
@@ -16,6 +16,7 @@
package android.print;
+import android.os.ICancellationSignal;
import android.print.PageRange;
/**
@@ -24,6 +25,8 @@
* @hide
*/
oneway interface IWriteResultCallback {
+ void onWriteStarted(ICancellationSignal cancellation, int sequence);
void onWriteFinished(in PageRange[] pages, int sequence);
void onWriteFailed(CharSequence error, int sequence);
+ void onWriteCanceled(int sequence);
}
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index c6254e0..2810d55 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -151,6 +151,105 @@
mColorMode = colorMode;
}
+ /**
+ * Gets whether this print attributes are in portrait orientation,
+ * which is the media size is in portrait and all orientation dependent
+ * attributes such as resolution and margins are properly adjusted.
+ *
+ * @return Whether this print attributes are in portrait.
+ *
+ * @hide
+ */
+ public boolean isPortrait() {
+ return mMediaSize.isPortrait();
+ }
+
+ /**
+ * Gets a new print attributes instance which is in portrait orientation,
+ * which is the media size is in portrait and all orientation dependent
+ * attributes such as resolution and margins are properly adjusted.
+ *
+ * @return New instance in portrait orientation if this one is in
+ * landscape, otherwise this instance.
+ *
+ * @hide
+ */
+ public PrintAttributes asPortrait() {
+ if (isPortrait()) {
+ return this;
+ }
+
+ PrintAttributes attributes = new PrintAttributes();
+
+ // Rotate the media size.
+ attributes.setMediaSize(getMediaSize().asPortrait());
+
+ // Rotate the resolution.
+ Resolution oldResolution = getResolution();
+ Resolution newResolution = new Resolution(
+ oldResolution.getId(),
+ oldResolution.getLabel(),
+ oldResolution.getVerticalDpi(),
+ oldResolution.getHorizontalDpi());
+ attributes.setResolution(newResolution);
+
+ // Rotate the physical margins.
+ Margins oldMinMargins = getMinMargins();
+ Margins newMinMargins = new Margins(
+ oldMinMargins.getBottomMils(),
+ oldMinMargins.getLeftMils(),
+ oldMinMargins.getTopMils(),
+ oldMinMargins.getRightMils());
+ attributes.setMinMargins(newMinMargins);
+
+ attributes.setColorMode(getColorMode());
+
+ return attributes;
+ }
+
+ /**
+ * Gets a new print attributes instance which is in landscape orientation,
+ * which is the media size is in landscape and all orientation dependent
+ * attributes such as resolution and margins are properly adjusted.
+ *
+ * @return New instance in landscape orientation if this one is in
+ * portrait, otherwise this instance.
+ *
+ * @hide
+ */
+ public PrintAttributes asLandscape() {
+ if (!isPortrait()) {
+ return this;
+ }
+
+ PrintAttributes attributes = new PrintAttributes();
+
+ // Rotate the media size.
+ attributes.setMediaSize(getMediaSize().asLandscape());
+
+ // Rotate the resolution.
+ Resolution oldResolution = getResolution();
+ Resolution newResolution = new Resolution(
+ oldResolution.getId(),
+ oldResolution.getLabel(),
+ oldResolution.getVerticalDpi(),
+ oldResolution.getHorizontalDpi());
+ attributes.setResolution(newResolution);
+
+ // Rotate the physical margins.
+ Margins oldMinMargins = getMinMargins();
+ Margins newMargins = new Margins(
+ oldMinMargins.getTopMils(),
+ oldMinMargins.getRightMils(),
+ oldMinMargins.getBottomMils(),
+ oldMinMargins.getLeftMils());
+ attributes.setMinMargins(newMargins);
+
+ attributes.setColorMode(getColorMode());
+
+ return attributes;
+ }
+
@Override
public void writeToParcel(Parcel parcel, int flags) {
if (mMediaSize != null) {
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 811751d..9361286 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -24,6 +24,7 @@
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
+import android.os.ICancellationSignal;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -41,6 +42,7 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -50,12 +52,12 @@
* <p>
* To obtain a handle to the print manager do the following:
* </p>
- *
+ *
* <pre>
* PrintManager printManager =
* (PrintManager) context.getSystemService(Context.PRINT_SERVICE);
* </pre>
- *
+ *
* <h3>Print mechanics</h3>
* <p>
* The key idea behind printing on the platform is that the content to be printed
@@ -344,7 +346,7 @@
try {
mService.cancelPrintJob(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error cancleing a print job: " + printJobId, re);
+ Log.e(LOG_TAG, "Error canceling a print job: " + printJobId, re);
}
}
@@ -505,30 +507,17 @@
private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub
implements ActivityLifecycleCallbacks {
-
private final Object mLock = new Object();
- private CancellationSignal mLayoutOrWriteCancellation;
+ private Activity mActivity; // Strong reference OK - cleared in destroy
- private Activity mActivity; // Strong reference OK - cleared in finish()
+ private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK - cleared in destroy
- private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK - cleared in finish
+ private Handler mHandler; // Strong reference OK - cleared in destroy
- private Handler mHandler; // Strong reference OK - cleared in finish()
+ private IPrintDocumentAdapterObserver mObserver; // Strong reference OK - cleared in destroy
- private IPrintDocumentAdapterObserver mObserver; // Strong reference OK - cleared in finish
-
- private LayoutSpec mLastLayoutSpec;
-
- private WriteSpec mLastWriteSpec;
-
- private boolean mStartReqeusted;
- private boolean mStarted;
-
- private boolean mFinishRequested;
- private boolean mFinished;
-
- private boolean mDestroyed;
+ private DestroyableCallback mPendingCallback;
public PrintDocumentAdapterDelegate(Activity activity,
PrintDocumentAdapter documentAdapter) {
@@ -542,11 +531,10 @@
public void setObserver(IPrintDocumentAdapterObserver observer) {
final boolean destroyed;
synchronized (mLock) {
- if (!mDestroyed) {
- mObserver = observer;
- }
- destroyed = mDestroyed;
+ mObserver = observer;
+ destroyed = isDestroyedLocked();
}
+
if (destroyed) {
try {
observer.onDestroy();
@@ -559,126 +547,89 @@
@Override
public void start() {
synchronized (mLock) {
- // Started called or finish called or destroyed - nothing to do.
- if (mStartReqeusted || mFinishRequested || mDestroyed) {
- return;
+ // If destroyed the handler is null.
+ if (!isDestroyedLocked()) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_START,
+ mDocumentAdapter).sendToTarget();
}
-
- mStartReqeusted = true;
-
- doPendingWorkLocked();
}
}
@Override
public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
ILayoutResultCallback callback, Bundle metadata, int sequence) {
- final boolean destroyed;
- synchronized (mLock) {
- destroyed = mDestroyed;
- // If start called and not finished called and not destroyed - do some work.
- if (mStartReqeusted && !mFinishRequested && !mDestroyed) {
- // Layout cancels write and overrides layout.
- if (mLastWriteSpec != null) {
- IoUtils.closeQuietly(mLastWriteSpec.fd);
- mLastWriteSpec = null;
- }
- mLastLayoutSpec = new LayoutSpec();
- mLastLayoutSpec.callback = callback;
- mLastLayoutSpec.oldAttributes = oldAttributes;
- mLastLayoutSpec.newAttributes = newAttributes;
- mLastLayoutSpec.metadata = metadata;
- mLastLayoutSpec.sequence = sequence;
-
- // Cancel the previous cancellable operation.When the
- // cancellation completes we will do the pending work.
- if (cancelPreviousCancellableOperationLocked()) {
- return;
- }
-
- doPendingWorkLocked();
- }
+ ICancellationSignal cancellationTransport = CancellationSignal.createTransport();
+ try {
+ callback.onLayoutStarted(cancellationTransport, sequence);
+ } catch (RemoteException re) {
+ // The spooler is dead - can't recover.
+ Log.e(LOG_TAG, "Error notifying for layout start", re);
+ return;
}
- if (destroyed) {
- try {
- callback.onLayoutFailed(null, sequence);
- } catch (RemoteException re) {
- Log.i(LOG_TAG, "Error notifying for cancelled layout", re);
+
+ synchronized (mLock) {
+ // If destroyed the handler is null.
+ if (isDestroyedLocked()) {
+ return;
}
+
+ CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
+ cancellationTransport);
+
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = mDocumentAdapter;
+ args.arg2 = oldAttributes;
+ args.arg3 = newAttributes;
+ args.arg4 = cancellationSignal;
+ args.arg5 = new MyLayoutResultCallback(callback, sequence);
+ args.arg6 = metadata;
+
+ mHandler.obtainMessage(MyHandler.MSG_ON_LAYOUT, args).sendToTarget();
}
}
@Override
public void write(PageRange[] pages, ParcelFileDescriptor fd,
IWriteResultCallback callback, int sequence) {
- final boolean destroyed;
- synchronized (mLock) {
- destroyed = mDestroyed;
- // If start called and not finished called and not destroyed - do some work.
- if (mStartReqeusted && !mFinishRequested && !mDestroyed) {
- // Write cancels previous writes.
- if (mLastWriteSpec != null) {
- IoUtils.closeQuietly(mLastWriteSpec.fd);
- mLastWriteSpec = null;
- }
- mLastWriteSpec = new WriteSpec();
- mLastWriteSpec.callback = callback;
- mLastWriteSpec.pages = pages;
- mLastWriteSpec.fd = fd;
- mLastWriteSpec.sequence = sequence;
-
- // Cancel the previous cancellable operation.When the
- // cancellation completes we will do the pending work.
- if (cancelPreviousCancellableOperationLocked()) {
- return;
- }
-
- doPendingWorkLocked();
- }
+ ICancellationSignal cancellationTransport = CancellationSignal.createTransport();
+ try {
+ callback.onWriteStarted(cancellationTransport, sequence);
+ } catch (RemoteException re) {
+ // The spooler is dead - can't recover.
+ Log.e(LOG_TAG, "Error notifying for write start", re);
+ return;
}
- if (destroyed) {
- try {
- callback.onWriteFailed(null, sequence);
- } catch (RemoteException re) {
- Log.i(LOG_TAG, "Error notifying for cancelled write", re);
+
+ synchronized (mLock) {
+ // If destroyed the handler is null.
+ if (isDestroyedLocked()) {
+ return;
}
+
+ CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
+ cancellationTransport);
+
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = mDocumentAdapter;
+ args.arg2 = pages;
+ args.arg3 = fd;
+ args.arg4 = cancellationSignal;
+ args.arg5 = new MyWriteResultCallback(callback, fd, sequence);
+
+ mHandler.obtainMessage(MyHandler.MSG_ON_WRITE, args).sendToTarget();
}
}
@Override
public void finish() {
synchronized (mLock) {
- // Start not called or finish called or destroyed - nothing to do.
- if (!mStartReqeusted || mFinishRequested || mDestroyed) {
- return;
+ // If destroyed the handler is null.
+ if (!isDestroyedLocked()) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_FINISH,
+ mDocumentAdapter).sendToTarget();
}
-
- mFinishRequested = true;
-
- // When the current write or layout complete we
- // will do the pending work.
- if (mLastLayoutSpec != null || mLastWriteSpec != null) {
- if (DEBUG) {
- Log.i(LOG_TAG, "Waiting for current operation");
- }
- return;
- }
-
- doPendingWorkLocked();
- }
- }
-
- @Override
- public void cancel() {
- // Start not called or finish called or destroyed - nothing to do.
- if (!mStartReqeusted || mFinishRequested || mDestroyed) {
- return;
- }
- // Request cancellation of pending work if needed.
- synchronized (mLock) {
- cancelPreviousCancellableOperationLocked();
}
}
@@ -719,20 +670,14 @@
// Note the the spooler has a death recipient that observes if
// this process gets killed so we cover the case of onDestroy not
// being called due to this process being killed to reclaim memory.
- final IPrintDocumentAdapterObserver observer;
+ IPrintDocumentAdapterObserver observer = null;
synchronized (mLock) {
if (activity == mActivity) {
- mDestroyed = true;
observer = mObserver;
- clearLocked();
- } else {
- observer = null;
- activity = null;
+ destroyLocked();
}
}
if (observer != null) {
- activity.getApplication().unregisterActivityLifecycleCallbacks(
- PrintDocumentAdapterDelegate.this);
try {
observer.onDestroy();
} catch (RemoteException re) {
@@ -741,67 +686,39 @@
}
}
- private boolean isFinished() {
- return mDocumentAdapter == null;
+ private boolean isDestroyedLocked() {
+ return (mActivity == null);
}
- private void clearLocked() {
+ private void destroyLocked() {
+ mActivity.getApplication().unregisterActivityLifecycleCallbacks(
+ PrintDocumentAdapterDelegate.this);
mActivity = null;
+
mDocumentAdapter = null;
+
+ // This method is only called from the main thread, so
+ // clearing the messages guarantees that any time a
+ // message is handled we are not in a destroyed state.
+ mHandler.removeMessages(MyHandler.MSG_ON_START);
+ mHandler.removeMessages(MyHandler.MSG_ON_LAYOUT);
+ mHandler.removeMessages(MyHandler.MSG_ON_WRITE);
+ mHandler.removeMessages(MyHandler.MSG_ON_FINISH);
mHandler = null;
- mLayoutOrWriteCancellation = null;
- mLastLayoutSpec = null;
- if (mLastWriteSpec != null) {
- IoUtils.closeQuietly(mLastWriteSpec.fd);
- mLastWriteSpec = null;
+
+ mObserver = null;
+
+ if (mPendingCallback != null) {
+ mPendingCallback.destroy();
+ mPendingCallback = null;
}
}
- private boolean cancelPreviousCancellableOperationLocked() {
- if (mLayoutOrWriteCancellation != null) {
- mLayoutOrWriteCancellation.cancel();
- if (DEBUG) {
- Log.i(LOG_TAG, "Cancelling previous operation");
- }
- return true;
- }
- return false;
- }
-
- private void doPendingWorkLocked() {
- if (mStartReqeusted && !mStarted) {
- mStarted = true;
- mHandler.sendEmptyMessage(MyHandler.MSG_START);
- } else if (mLastLayoutSpec != null) {
- mHandler.sendEmptyMessage(MyHandler.MSG_LAYOUT);
- } else if (mLastWriteSpec != null) {
- mHandler.sendEmptyMessage(MyHandler.MSG_WRITE);
- } else if (mFinishRequested && !mFinished) {
- mFinished = true;
- mHandler.sendEmptyMessage(MyHandler.MSG_FINISH);
- }
- }
-
- private class LayoutSpec {
- ILayoutResultCallback callback;
- PrintAttributes oldAttributes;
- PrintAttributes newAttributes;
- Bundle metadata;
- int sequence;
- }
-
- private class WriteSpec {
- IWriteResultCallback callback;
- PageRange[] pages;
- ParcelFileDescriptor fd;
- int sequence;
- }
-
private final class MyHandler extends Handler {
- public static final int MSG_START = 1;
- public static final int MSG_LAYOUT = 2;
- public static final int MSG_WRITE = 3;
- public static final int MSG_FINISH = 4;
+ public static final int MSG_ON_START = 1;
+ public static final int MSG_ON_LAYOUT = 2;
+ public static final int MSG_ON_WRITE = 3;
+ public static final int MSG_ON_FINISH = 4;
public MyHandler(Looper looper) {
super(looper, null, true);
@@ -809,84 +726,71 @@
@Override
public void handleMessage(Message message) {
- if (isFinished()) {
- return;
- }
switch (message.what) {
- case MSG_START: {
- final PrintDocumentAdapter adapter;
- synchronized (mLock) {
- adapter = mDocumentAdapter;
- }
- if (adapter != null) {
- adapter.onStart();
- }
- } break;
-
- case MSG_LAYOUT: {
- final PrintDocumentAdapter adapter;
- final CancellationSignal cancellation;
- final LayoutSpec layoutSpec;
-
- synchronized (mLock) {
- adapter = mDocumentAdapter;
- layoutSpec = mLastLayoutSpec;
- mLastLayoutSpec = null;
- cancellation = new CancellationSignal();
- mLayoutOrWriteCancellation = cancellation;
- }
-
- if (layoutSpec != null && adapter != null) {
- if (DEBUG) {
- Log.i(LOG_TAG, "Performing layout");
- }
- adapter.onLayout(layoutSpec.oldAttributes,
- layoutSpec.newAttributes, cancellation,
- new MyLayoutResultCallback(layoutSpec.callback,
- layoutSpec.sequence), layoutSpec.metadata);
- }
- } break;
-
- case MSG_WRITE: {
- final PrintDocumentAdapter adapter;
- final CancellationSignal cancellation;
- final WriteSpec writeSpec;
-
- synchronized (mLock) {
- adapter = mDocumentAdapter;
- writeSpec = mLastWriteSpec;
- mLastWriteSpec = null;
- cancellation = new CancellationSignal();
- mLayoutOrWriteCancellation = cancellation;
- }
-
- if (writeSpec != null && adapter != null) {
- if (DEBUG) {
- Log.i(LOG_TAG, "Performing write");
- }
- adapter.onWrite(writeSpec.pages, writeSpec.fd,
- cancellation, new MyWriteResultCallback(writeSpec.callback,
- writeSpec.fd, writeSpec.sequence));
- }
- } break;
-
- case MSG_FINISH: {
+ case MSG_ON_START: {
if (DEBUG) {
- Log.i(LOG_TAG, "Performing finish");
+ Log.i(LOG_TAG, "onStart()");
}
- final PrintDocumentAdapter adapter;
- final Activity activity;
+
+ ((PrintDocumentAdapter) message.obj).onStart();
+ } break;
+
+ case MSG_ON_LAYOUT: {
+ SomeArgs args = (SomeArgs) message.obj;
+ PrintDocumentAdapter adapter = (PrintDocumentAdapter) args.arg1;
+ PrintAttributes oldAttributes = (PrintAttributes) args.arg2;
+ PrintAttributes newAttributes = (PrintAttributes) args.arg3;
+ CancellationSignal cancellation = (CancellationSignal) args.arg4;
+ LayoutResultCallback callback = (LayoutResultCallback) args.arg5;
+ Bundle metadata = (Bundle) args.arg6;
+ args.recycle();
+
+ if (DEBUG) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("PrintDocumentAdapter#onLayout() {\n");
+ builder.append("\n oldAttributes:").append(oldAttributes);
+ builder.append("\n newAttributes:").append(newAttributes);
+ builder.append("\n preview:").append(metadata.getBoolean(
+ PrintDocumentAdapter.EXTRA_PRINT_PREVIEW));
+ builder.append("\n}");
+ Log.i(LOG_TAG, builder.toString());
+ }
+
+ adapter.onLayout(oldAttributes, newAttributes, cancellation,
+ callback, metadata);
+ } break;
+
+ case MSG_ON_WRITE: {
+ SomeArgs args = (SomeArgs) message.obj;
+ PrintDocumentAdapter adapter = (PrintDocumentAdapter) args.arg1;
+ PageRange[] pages = (PageRange[]) args.arg2;
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args.arg3;
+ CancellationSignal cancellation = (CancellationSignal) args.arg4;
+ WriteResultCallback callback = (WriteResultCallback) args.arg5;
+ args.recycle();
+
+ if (DEBUG) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("PrintDocumentAdapter#onWrite() {\n");
+ builder.append("\n pages:").append(Arrays.toString(pages));
+ builder.append("\n}");
+ Log.i(LOG_TAG, builder.toString());
+ }
+
+ adapter.onWrite(pages, fd, cancellation, callback);
+ } break;
+
+ case MSG_ON_FINISH: {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "onFinish()");
+ }
+
+ ((PrintDocumentAdapter) message.obj).onFinish();
+
+ // Done printing, so destroy this instance as it
+ // should not be used anymore.
synchronized (mLock) {
- adapter = mDocumentAdapter;
- activity = mActivity;
- clearLocked();
- }
- if (adapter != null) {
- adapter.onFinish();
- }
- if (activity != null) {
- activity.getApplication().unregisterActivityLifecycleCallbacks(
- PrintDocumentAdapterDelegate.this);
+ destroyLocked();
}
} break;
@@ -898,7 +802,12 @@
}
}
- private final class MyLayoutResultCallback extends LayoutResultCallback {
+ private interface DestroyableCallback {
+ public void destroy();
+ }
+
+ private final class MyLayoutResultCallback extends LayoutResultCallback
+ implements DestroyableCallback {
private ILayoutResultCallback mCallback;
private final int mSequence;
@@ -910,25 +819,31 @@
@Override
public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
- if (info == null) {
- throw new NullPointerException("document info cannot be null");
- }
final ILayoutResultCallback callback;
synchronized (mLock) {
- if (mDestroyed) {
- Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
- + "finish the printing activity before print completion?");
- return;
- }
callback = mCallback;
- clearLocked();
}
- if (callback != null) {
+
+ // If the callback is null we are destroyed.
+ if (callback == null) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion "
+ + "or did you invoke a callback after finish?");
+ return;
+ }
+
+ try {
+ if (info == null) {
+ throw new NullPointerException("document info cannot be null");
+ }
+
try {
callback.onLayoutFinished(info, changed, mSequence);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error calling onLayoutFinished", re);
}
+ } finally {
+ destroy();
}
}
@@ -936,46 +851,64 @@
public void onLayoutFailed(CharSequence error) {
final ILayoutResultCallback callback;
synchronized (mLock) {
- if (mDestroyed) {
- Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
- + "finish the printing activity before print completion?");
- return;
- }
callback = mCallback;
- clearLocked();
}
- if (callback != null) {
- try {
- callback.onLayoutFailed(error, mSequence);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling onLayoutFailed", re);
- }
+
+ // If the callback is null we are destroyed.
+ if (callback == null) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion "
+ + "or did you invoke a callback after finish?");
+ return;
+ }
+
+ try {
+ callback.onLayoutFailed(error, mSequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onLayoutFailed", re);
+ } finally {
+ destroy();
}
}
@Override
public void onLayoutCancelled() {
+ final ILayoutResultCallback callback;
synchronized (mLock) {
- if (mDestroyed) {
- Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
- + "finish the printing activity before print completion?");
- return;
- }
- clearLocked();
+ callback = mCallback;
+ }
+
+ // If the callback is null we are destroyed.
+ if (callback == null) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion "
+ + "or did you invoke a callback after finish?");
+ return;
+ }
+
+ try {
+ callback.onLayoutCanceled(mSequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onLayoutFailed", re);
+ } finally {
+ destroy();
}
}
- private void clearLocked() {
- mLayoutOrWriteCancellation = null;
- mCallback = null;
- doPendingWorkLocked();
+ @Override
+ public void destroy() {
+ synchronized (mLock) {
+ mCallback = null;
+ mPendingCallback = null;
+ }
}
}
- private final class MyWriteResultCallback extends WriteResultCallback {
+ private final class MyWriteResultCallback extends WriteResultCallback
+ implements DestroyableCallback {
private ParcelFileDescriptor mFd;
- private int mSequence;
private IWriteResultCallback mCallback;
+ private final int mSequence;
public MyWriteResultCallback(IWriteResultCallback callback,
ParcelFileDescriptor fd, int sequence) {
@@ -988,26 +921,32 @@
public void onWriteFinished(PageRange[] pages) {
final IWriteResultCallback callback;
synchronized (mLock) {
- if (mDestroyed) {
- Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
- + "finish the printing activity before print completion?");
- return;
- }
callback = mCallback;
- clearLocked();
}
- if (pages == null) {
- throw new IllegalArgumentException("pages cannot be null");
+
+ // If the callback is null we are destroyed.
+ if (callback == null) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion "
+ + "or did you invoke a callback after finish?");
+ return;
}
- if (pages.length == 0) {
- throw new IllegalArgumentException("pages cannot be empty");
- }
- if (callback != null) {
+
+ try {
+ if (pages == null) {
+ throw new IllegalArgumentException("pages cannot be null");
+ }
+ if (pages.length == 0) {
+ throw new IllegalArgumentException("pages cannot be empty");
+ }
+
try {
callback.onWriteFinished(pages, mSequence);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error calling onWriteFinished", re);
}
+ } finally {
+ destroy();
}
}
@@ -1015,41 +954,58 @@
public void onWriteFailed(CharSequence error) {
final IWriteResultCallback callback;
synchronized (mLock) {
- if (mDestroyed) {
- Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
- + "finish the printing activity before print completion?");
- return;
- }
callback = mCallback;
- clearLocked();
}
- if (callback != null) {
- try {
- callback.onWriteFailed(error, mSequence);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling onWriteFailed", re);
- }
+
+ // If the callback is null we are destroyed.
+ if (callback == null) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion "
+ + "or did you invoke a callback after finish?");
+ return;
+ }
+
+ try {
+ callback.onWriteFailed(error, mSequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onWriteFailed", re);
+ } finally {
+ destroy();
}
}
@Override
public void onWriteCancelled() {
+ final IWriteResultCallback callback;
synchronized (mLock) {
- if (mDestroyed) {
- Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
- + "finish the printing activity before print completion?");
- return;
- }
- clearLocked();
+ callback = mCallback;
+ }
+
+ // If the callback is null we are destroyed.
+ if (callback == null) {
+ Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+ + "finish the printing activity before print completion "
+ + "or did you invoke a callback after finish?");
+ return;
+ }
+
+ try {
+ callback.onWriteCanceled(mSequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling onWriteCanceled", re);
+ } finally {
+ destroy();
}
}
- private void clearLocked() {
- mLayoutOrWriteCancellation = null;
- IoUtils.closeQuietly(mFd);
- mCallback = null;
- mFd = null;
- doPendingWorkLocked();
+ @Override
+ public void destroy() {
+ synchronized (mLock) {
+ IoUtils.closeQuietly(mFd);
+ mCallback = null;
+ mFd = null;
+ mPendingCallback = null;
+ }
}
}
}
diff --git a/core/java/android/print/PrinterDiscoverySession.java b/core/java/android/print/PrinterDiscoverySession.java
index d32b71b..abb441b 100644
--- a/core/java/android/print/PrinterDiscoverySession.java
+++ b/core/java/android/print/PrinterDiscoverySession.java
@@ -72,9 +72,9 @@
}
}
- public final void startPrinterDisovery(List<PrinterId> priorityList) {
+ public final void startPrinterDiscovery(List<PrinterId> priorityList) {
if (isDestroyed()) {
- Log.w(LOG_TAG, "Ignoring start printers dsicovery - session destroyed");
+ Log.w(LOG_TAG, "Ignoring start printers discovery - session destroyed");
return;
}
if (!mIsPrinterDiscoveryStarted) {
@@ -122,7 +122,7 @@
try {
mPrintManager.stopPrinterStateTracking(printerId, mUserId);
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error stoping printer state tracking", re);
+ Log.e(LOG_TAG, "Error stopping printer state tracking", re);
}
}
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index eb0ac2e..1557ab0 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -201,9 +201,9 @@
* should build another one using the {@link PrintJobInfo.Builder} class. You
* can specify any standard properties and add advanced, printer specific,
* ones via {@link PrintJobInfo.Builder#putAdvancedOption(String, String)
- * PrintJobInfo.Builder#putAdvancedOption(String, String)} and {@link
+ * PrintJobInfo.Builder.putAdvancedOption(String, String)} and {@link
* PrintJobInfo.Builder#putAdvancedOption(String, int)
- * PrintJobInfo.Builder#putAdvancedOption(String, int)}. The advanced options
+ * PrintJobInfo.Builder.putAdvancedOption(String, int)}. The advanced options
* are not interpreted by the system, they will not be visible to applications,
* and can only be accessed by your print service via {@link
* PrintJob#getAdvancedStringOption(String) PrintJob.getAdvancedStringOption(String)}
@@ -212,14 +212,26 @@
* <p>
* If the advanced print options activity offers changes to the standard print
* options, you can get the current {@link android.print.PrinterInfo} using the
- * "android.intent.extra.print.EXTRA_PRINTER_INFO" extra which will allow you to
- * present the user with UI options supported by the current printer. For example,
- * if the current printer does not support a give media size, you should not
- * offer it in the advanced print options dialog.
+ * {@link #EXTRA_PRINTER_INFO} extra which will allow you to present the user
+ * with UI options supported by the current printer. For example, if the current
+ * printer does not support a given media size, you should not offer it in the
+ * advanced print options UI.
* </p>
+ *
+ * @see #EXTRA_PRINTER_INFO
*/
public static final String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO";
+ /**
+ * If you declared an optional activity with advanced print options via the
+ * {@link R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
+ * attribute, this extra is used to pass in the currently selected printer's
+ * {@link android.print.PrinterInfo} to your activity allowing you to inspect it.
+ *
+ * @see #EXTRA_PRINT_JOB_INFO
+ */
+ public static final String EXTRA_PRINTER_INFO = "android.intent.extra.print.PRINTER_INFO";
+
private Handler mHandler;
private IPrintServiceClient mClient;
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index a34d9c3..3853003 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -25,6 +25,7 @@
import android.database.DatabaseUtils;
import android.graphics.BitmapFactory;
import android.net.Uri;
+import android.os.Build;
import android.provider.BrowserContract.Bookmarks;
import android.provider.BrowserContract.Combined;
import android.provider.BrowserContract.History;
@@ -155,8 +156,8 @@
* @param title Title for the bookmark. Can be null or empty string.
* @param url Url for the bookmark. Can be null or empty string.
*/
- public static final void saveBookmark(Context c,
- String title,
+ public static final void saveBookmark(Context c,
+ String title,
String url) {
Intent i = new Intent(Intent.ACTION_INSERT, Browser.BOOKMARKS_URI);
i.putExtra("title", title);
@@ -233,10 +234,10 @@
*
* @param cr The ContentResolver used to access the database.
*/
- public static final Cursor getAllBookmarks(ContentResolver cr) throws
+ public static final Cursor getAllBookmarks(ContentResolver cr) throws
IllegalStateException {
return cr.query(Bookmarks.CONTENT_URI,
- new String[] { Bookmarks.URL },
+ new String[] { Bookmarks.URL },
Bookmarks.IS_FOLDER + " = 0", null, null);
}
@@ -397,19 +398,17 @@
// TODO make a single request to the provider to do this in a single transaction
Cursor cursor = null;
try {
-
+
// Select non-bookmark history, ordered by date
cursor = cr.query(History.CONTENT_URI,
new String[] { History._ID, History.URL, History.DATE_LAST_VISITED },
null, null, History.DATE_LAST_VISITED + " ASC");
if (cursor.moveToFirst() && cursor.getCount() >= MAX_HISTORY_COUNT) {
- final WebIconDatabase iconDb = WebIconDatabase.getInstance();
/* eliminate oldest history items */
for (int i = 0; i < TRUNCATE_N_OLDEST; i++) {
cr.delete(ContentUris.withAppendedId(History.CONTENT_URI, cursor.getLong(0)),
- null, null);
- iconDb.releaseIconForPageUrl(cursor.getString(1));
+ null, null);
if (!cursor.moveToNext()) break;
}
}
@@ -469,13 +468,6 @@
cursor = cr.query(History.CONTENT_URI, new String[] { History.URL }, whereClause,
null, null);
if (cursor.moveToFirst()) {
- final WebIconDatabase iconDb = WebIconDatabase.getInstance();
- do {
- // Delete favicons
- // TODO don't release if the URL is bookmarked
- iconDb.releaseIconForPageUrl(cursor.getString(0));
- } while (cursor.moveToNext());
-
cr.delete(History.CONTENT_URI, whereClause, null);
}
} catch (IllegalStateException e) {
@@ -520,7 +512,7 @@
* @param cr The ContentResolver used to access the database.
* @param url url to remove.
*/
- public static final void deleteFromHistory(ContentResolver cr,
+ public static final void deleteFromHistory(ContentResolver cr,
String url) {
cr.delete(History.CONTENT_URI, History.URL + "=?", new String[] { url });
}
@@ -554,7 +546,7 @@
Log.e(LOGTAG, "clearSearches", e);
}
}
-
+
/**
* Request all icons from the database. This call must either be called
* in the main thread or have had Looper.prepare() invoked in the calling
@@ -563,12 +555,12 @@
* @param cr The ContentResolver used to access the database.
* @param where Clause to be used to limit the query from the database.
* Must be an allowable string to be passed into a database query.
- * @param listener IconListener that gets the icons once they are
+ * @param listener IconListener that gets the icons once they are
* retrieved.
*/
public static final void requestAllIcons(ContentResolver cr, String where,
WebIconDatabase.IconListener listener) {
- WebIconDatabase.getInstance().bulkRequestIconForPageUrl(cr, where, listener);
+ // Do nothing: this is no longer used.
}
/**
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index ba66e65..1e7d7f1 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -7963,8 +7963,7 @@
actualContext = ((ContextWrapper) actualContext).getBaseContext();
}
final int intentFlags = (actualContext instanceof Activity)
- ? Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
- : Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK;
+ ? 0 : Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK;
// Launch pivot dialog through intent for now
final Intent intent = new Intent(ACTION_QUICK_CONTACT).addFlags(intentFlags);
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 6b8e2de..327fe4a 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -60,7 +60,8 @@
* <p>
* All client apps must hold a valid URI permission grant to access documents,
* typically issued when a user makes a selection through
- * {@link Intent#ACTION_OPEN_DOCUMENT} or {@link Intent#ACTION_CREATE_DOCUMENT}.
+ * {@link Intent#ACTION_OPEN_DOCUMENT}, {@link Intent#ACTION_CREATE_DOCUMENT},
+ * or {@link Intent#ACTION_OPEN_DOCUMENT_TREE}.
*
* @see DocumentsProvider
*/
@@ -73,8 +74,8 @@
// content://com.example/root/sdcard/search/?query=pony
// content://com.example/document/12/
// content://com.example/document/12/children/
- // content://com.example/via/12/document/24/
- // content://com.example/via/12/document/24/children/
+ // content://com.example/tree/12/document/24/
+ // content://com.example/tree/12/document/24/children/
private DocumentsContract() {
}
@@ -441,12 +442,13 @@
public static final int FLAG_SUPPORTS_SEARCH = 1 << 3;
/**
- * Flag indicating that this root supports directory selection.
+ * Flag indicating that this root supports testing parent child
+ * relationships.
*
* @see #COLUMN_FLAGS
* @see DocumentsProvider#isChildDocument(String, String)
*/
- public static final int FLAG_SUPPORTS_DIR_SELECTION = 1 << 4;
+ public static final int FLAG_SUPPORTS_IS_CHILD = 1 << 4;
/**
* Flag indicating that this root is currently empty. This may be used
@@ -518,7 +520,7 @@
private static final String PATH_DOCUMENT = "document";
private static final String PATH_CHILDREN = "children";
private static final String PATH_SEARCH = "search";
- private static final String PATH_VIA = "via";
+ private static final String PATH_TREE = "tree";
private static final String PARAM_QUERY = "query";
private static final String PARAM_MANAGE = "manage";
@@ -564,17 +566,17 @@
* Build URI representing access to descendant documents of the given
* {@link Document#COLUMN_DOCUMENT_ID}.
*
- * @see #getViaDocumentId(Uri)
+ * @see #getTreeDocumentId(Uri)
*/
- public static Uri buildViaUri(String authority, String documentId) {
+ public static Uri buildTreeDocumentUri(String authority, String documentId) {
return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority)
- .appendPath(PATH_VIA).appendPath(documentId).build();
+ .appendPath(PATH_TREE).appendPath(documentId).build();
}
/**
- * Build URI representing the given {@link Document#COLUMN_DOCUMENT_ID} in a
- * document provider. When queried, a provider will return a single row with
- * columns defined by {@link Document}.
+ * Build URI representing the target {@link Document#COLUMN_DOCUMENT_ID} in
+ * a document provider. When queried, a provider will return a single row
+ * with columns defined by {@link Document}.
*
* @see DocumentsProvider#queryDocument(String, String[])
* @see #getDocumentId(Uri)
@@ -585,42 +587,46 @@
}
/**
- * Build URI representing the given {@link Document#COLUMN_DOCUMENT_ID} in a
- * document provider. Instead of directly accessing the target document,
- * gain access via another document. The target document must be a
- * descendant (child, grandchild, etc) of the via document.
+ * Build URI representing the target {@link Document#COLUMN_DOCUMENT_ID} in
+ * a document provider. When queried, a provider will return a single row
+ * with columns defined by {@link Document}.
+ * <p>
+ * However, instead of directly accessing the target document, the returned
+ * URI will leverage access granted through a subtree URI, typically
+ * returned by {@link Intent#ACTION_OPEN_DOCUMENT_TREE}. The target document
+ * must be a descendant (child, grandchild, etc) of the subtree.
* <p>
* This is typically used to access documents under a user-selected
- * directory, since it doesn't require the user to separately confirm each
- * new document access.
+ * directory tree, since it doesn't require the user to separately confirm
+ * each new document access.
*
- * @param viaUri a related document (directory) that the caller is
- * leveraging to gain access to the target document. The target
- * document must be a descendant of this directory.
+ * @param treeUri the subtree to leverage to gain access to the target
+ * document. The target directory must be a descendant of this
+ * subtree.
* @param documentId the target document, which the caller may not have
* direct access to.
- * @see Intent#ACTION_PICK_DIRECTORY
+ * @see Intent#ACTION_OPEN_DOCUMENT_TREE
* @see DocumentsProvider#isChildDocument(String, String)
* @see #buildDocumentUri(String, String)
*/
- public static Uri buildDocumentViaUri(Uri viaUri, String documentId) {
+ public static Uri buildDocumentUriUsingTree(Uri treeUri, String documentId) {
return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
- .authority(viaUri.getAuthority()).appendPath(PATH_VIA)
- .appendPath(getViaDocumentId(viaUri)).appendPath(PATH_DOCUMENT)
+ .authority(treeUri.getAuthority()).appendPath(PATH_TREE)
+ .appendPath(getTreeDocumentId(treeUri)).appendPath(PATH_DOCUMENT)
.appendPath(documentId).build();
}
/** {@hide} */
- public static Uri buildDocumentMaybeViaUri(Uri baseUri, String documentId) {
- if (isViaUri(baseUri)) {
- return buildDocumentViaUri(baseUri, documentId);
+ public static Uri buildDocumentUriMaybeUsingTree(Uri baseUri, String documentId) {
+ if (isTreeUri(baseUri)) {
+ return buildDocumentUriUsingTree(baseUri, documentId);
} else {
return buildDocumentUri(baseUri.getAuthority(), documentId);
}
}
/**
- * Build URI representing the children of the given directory in a document
+ * Build URI representing the children of the target directory in a document
* provider. When queried, a provider will return zero or more rows with
* columns defined by {@link Document}.
*
@@ -637,28 +643,33 @@
}
/**
- * Build URI representing the children of the given directory in a document
- * provider. Instead of directly accessing the target document, gain access
- * via another document. The target document must be a descendant (child,
- * grandchild, etc) of the via document.
+ * Build URI representing the children of the target directory in a document
+ * provider. When queried, a provider will return zero or more rows with
+ * columns defined by {@link Document}.
+ * <p>
+ * However, instead of directly accessing the target directory, the returned
+ * URI will leverage access granted through a subtree URI, typically
+ * returned by {@link Intent#ACTION_OPEN_DOCUMENT_TREE}. The target
+ * directory must be a descendant (child, grandchild, etc) of the subtree.
* <p>
* This is typically used to access documents under a user-selected
- * directory, since it doesn't require the user to separately confirm each
- * new document access.
+ * directory tree, since it doesn't require the user to separately confirm
+ * each new document access.
*
- * @param viaUri a related document (directory) that the caller is
- * leveraging to gain access to the target document. The target
- * document must be a descendant of this directory.
- * @param parentDocumentId the target document, which the caller may not
- * have direct access to.
- * @see Intent#ACTION_PICK_DIRECTORY
+ * @param treeUri the subtree to leverage to gain access to the target
+ * document. The target directory must be a descendant of this
+ * subtree.
+ * @param parentDocumentId the document to return children for, which the
+ * caller may not have direct access to, and which must be a
+ * directory with MIME type of {@link Document#MIME_TYPE_DIR}.
+ * @see Intent#ACTION_OPEN_DOCUMENT_TREE
* @see DocumentsProvider#isChildDocument(String, String)
* @see #buildChildDocumentsUri(String, String)
*/
- public static Uri buildChildDocumentsViaUri(Uri viaUri, String parentDocumentId) {
+ public static Uri buildChildDocumentsUriUsingTree(Uri treeUri, String parentDocumentId) {
return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
- .authority(viaUri.getAuthority()).appendPath(PATH_VIA)
- .appendPath(getViaDocumentId(viaUri)).appendPath(PATH_DOCUMENT)
+ .authority(treeUri.getAuthority()).appendPath(PATH_TREE)
+ .appendPath(getTreeDocumentId(treeUri)).appendPath(PATH_DOCUMENT)
.appendPath(parentDocumentId).appendPath(PATH_CHILDREN).build();
}
@@ -683,21 +694,24 @@
* {@link DocumentsProvider}.
*
* @see #buildDocumentUri(String, String)
- * @see #buildDocumentViaUri(Uri, String)
+ * @see #buildDocumentUriUsingTree(Uri, String)
*/
public static boolean isDocumentUri(Context context, Uri uri) {
final List<String> paths = uri.getPathSegments();
- if (paths.size() >= 2
- && (PATH_DOCUMENT.equals(paths.get(0)) || PATH_VIA.equals(paths.get(0)))) {
+ if (paths.size() == 2 && PATH_DOCUMENT.equals(paths.get(0))) {
+ return isDocumentsProvider(context, uri.getAuthority());
+ }
+ if (paths.size() == 4 && PATH_TREE.equals(paths.get(0))
+ && PATH_DOCUMENT.equals(paths.get(2))) {
return isDocumentsProvider(context, uri.getAuthority());
}
return false;
}
/** {@hide} */
- public static boolean isViaUri(Uri uri) {
+ public static boolean isTreeUri(Uri uri) {
final List<String> paths = uri.getPathSegments();
- return (paths.size() >= 2 && PATH_VIA.equals(paths.get(0)));
+ return (paths.size() >= 2 && PATH_TREE.equals(paths.get(0)));
}
private static boolean isDocumentsProvider(Context context, String authority) {
@@ -733,7 +747,7 @@
if (paths.size() >= 2 && PATH_DOCUMENT.equals(paths.get(0))) {
return paths.get(1);
}
- if (paths.size() >= 4 && PATH_VIA.equals(paths.get(0))
+ if (paths.size() >= 4 && PATH_TREE.equals(paths.get(0))
&& PATH_DOCUMENT.equals(paths.get(2))) {
return paths.get(3);
}
@@ -742,12 +756,10 @@
/**
* Extract the via {@link Document#COLUMN_DOCUMENT_ID} from the given URI.
- *
- * @see #isViaUri(Uri)
*/
- public static String getViaDocumentId(Uri documentUri) {
+ public static String getTreeDocumentId(Uri documentUri) {
final List<String> paths = documentUri.getPathSegments();
- if (paths.size() >= 2 && PATH_VIA.equals(paths.get(0))) {
+ if (paths.size() >= 2 && PATH_TREE.equals(paths.get(0))) {
return paths.get(1);
}
throw new IllegalArgumentException("Invalid URI: " + documentUri);
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 066b4aa..021fff4 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -20,10 +20,14 @@
import static android.provider.DocumentsContract.METHOD_CREATE_DOCUMENT;
import static android.provider.DocumentsContract.METHOD_DELETE_DOCUMENT;
import static android.provider.DocumentsContract.METHOD_RENAME_DOCUMENT;
+import static android.provider.DocumentsContract.buildDocumentUri;
+import static android.provider.DocumentsContract.buildDocumentUriMaybeUsingTree;
+import static android.provider.DocumentsContract.buildTreeDocumentUri;
import static android.provider.DocumentsContract.getDocumentId;
import static android.provider.DocumentsContract.getRootId;
import static android.provider.DocumentsContract.getSearchDocumentsQuery;
-import static android.provider.DocumentsContract.isViaUri;
+import static android.provider.DocumentsContract.getTreeDocumentId;
+import static android.provider.DocumentsContract.isTreeUri;
import android.content.ContentProvider;
import android.content.ContentResolver;
@@ -117,6 +121,7 @@
* </p>
*
* @see Intent#ACTION_OPEN_DOCUMENT
+ * @see Intent#ACTION_OPEN_DOCUMENT_TREE
* @see Intent#ACTION_CREATE_DOCUMENT
*/
public abstract class DocumentsProvider extends ContentProvider {
@@ -128,8 +133,8 @@
private static final int MATCH_SEARCH = 4;
private static final int MATCH_DOCUMENT = 5;
private static final int MATCH_CHILDREN = 6;
- private static final int MATCH_DOCUMENT_VIA = 7;
- private static final int MATCH_CHILDREN_VIA = 8;
+ private static final int MATCH_DOCUMENT_TREE = 7;
+ private static final int MATCH_CHILDREN_TREE = 8;
private String mAuthority;
@@ -149,8 +154,8 @@
mMatcher.addURI(mAuthority, "root/*/search", MATCH_SEARCH);
mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT);
mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN);
- mMatcher.addURI(mAuthority, "via/*/document/*", MATCH_DOCUMENT_VIA);
- mMatcher.addURI(mAuthority, "via/*/document/*/children", MATCH_CHILDREN_VIA);
+ mMatcher.addURI(mAuthority, "tree/*/document/*", MATCH_DOCUMENT_TREE);
+ mMatcher.addURI(mAuthority, "tree/*/document/*/children", MATCH_CHILDREN_TREE);
// Sanity check our setup
if (!info.exported) {
@@ -169,23 +174,24 @@
/**
* Test if a document is descendant (child, grandchild, etc) from the given
- * parent. Providers must override this to support directory selection. You
- * should avoid making network requests to keep this request fast.
+ * parent. For example, providers must implement this to support
+ * {@link Intent#ACTION_OPEN_DOCUMENT_TREE}. You should avoid making network
+ * requests to keep this request fast.
*
* @param parentDocumentId parent to verify against.
* @param documentId child to verify.
* @return if given document is a descendant of the given parent.
- * @see DocumentsContract.Root#FLAG_SUPPORTS_DIR_SELECTION
+ * @see DocumentsContract.Root#FLAG_SUPPORTS_IS_CHILD
*/
public boolean isChildDocument(String parentDocumentId, String documentId) {
return false;
}
/** {@hide} */
- private void enforceVia(Uri documentUri) {
- if (DocumentsContract.isViaUri(documentUri)) {
- final String parent = DocumentsContract.getViaDocumentId(documentUri);
- final String child = DocumentsContract.getDocumentId(documentUri);
+ private void enforceTree(Uri documentUri) {
+ if (isTreeUri(documentUri)) {
+ final String parent = getTreeDocumentId(documentUri);
+ final String child = getDocumentId(documentUri);
if (Objects.equals(parent, child)) {
return;
}
@@ -479,12 +485,12 @@
return querySearchDocuments(
getRootId(uri), getSearchDocumentsQuery(uri), projection);
case MATCH_DOCUMENT:
- case MATCH_DOCUMENT_VIA:
- enforceVia(uri);
+ case MATCH_DOCUMENT_TREE:
+ enforceTree(uri);
return queryDocument(getDocumentId(uri), projection);
case MATCH_CHILDREN:
- case MATCH_CHILDREN_VIA:
- enforceVia(uri);
+ case MATCH_CHILDREN_TREE:
+ enforceTree(uri);
if (DocumentsContract.isManageMode(uri)) {
return queryChildDocumentsForManage(
getDocumentId(uri), projection, sortOrder);
@@ -512,8 +518,8 @@
case MATCH_ROOT:
return DocumentsContract.Root.MIME_TYPE_ITEM;
case MATCH_DOCUMENT:
- case MATCH_DOCUMENT_VIA:
- enforceVia(uri);
+ case MATCH_DOCUMENT_TREE:
+ enforceTree(uri);
return getDocumentType(getDocumentId(uri));
default:
return null;
@@ -530,21 +536,20 @@
* call the superclass. If the superclass returns {@code null}, the subclass
* may implement custom behavior.
* <p>
- * This is typically used to resolve a "via" URI into a concrete document
+ * This is typically used to resolve a subtree URI into a concrete document
* reference, issuing a narrower single-document URI permission grant along
* the way.
*
- * @see DocumentsContract#buildDocumentViaUri(Uri, String)
+ * @see DocumentsContract#buildDocumentUriUsingTree(Uri, String)
*/
@Override
public Uri canonicalize(Uri uri) {
final Context context = getContext();
switch (mMatcher.match(uri)) {
- case MATCH_DOCUMENT_VIA:
- enforceVia(uri);
+ case MATCH_DOCUMENT_TREE:
+ enforceTree(uri);
- final Uri narrowUri = DocumentsContract.buildDocumentUri(uri.getAuthority(),
- DocumentsContract.getDocumentId(uri));
+ final Uri narrowUri = buildDocumentUri(uri.getAuthority(), getDocumentId(uri));
// Caller may only have prefix grant, so extend them a grant to
// the narrow URI.
@@ -628,7 +633,7 @@
throw new SecurityException(
"Requested authority " + authority + " doesn't match provider " + mAuthority);
}
- enforceVia(documentUri);
+ enforceTree(documentUri);
final Bundle out = new Bundle();
try {
@@ -641,8 +646,8 @@
// No need to issue new grants here, since caller either has
// manage permission or a prefix grant. We might generate a
- // "via" style URI if that's how they called us.
- final Uri newDocumentUri = DocumentsContract.buildDocumentMaybeViaUri(documentUri,
+ // tree style URI if that's how they called us.
+ final Uri newDocumentUri = buildDocumentUriMaybeUsingTree(documentUri,
newDocumentId);
out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
@@ -653,12 +658,12 @@
final String newDocumentId = renameDocument(documentId, displayName);
if (newDocumentId != null) {
- final Uri newDocumentUri = DocumentsContract.buildDocumentMaybeViaUri(
- documentUri, newDocumentId);
+ final Uri newDocumentUri = buildDocumentUriMaybeUsingTree(documentUri,
+ newDocumentId);
// If caller came in with a narrow grant, issue them a
// narrow grant for the newly renamed document.
- if (!isViaUri(newDocumentUri)) {
+ if (!isTreeUri(newDocumentUri)) {
final int modeFlags = getCallingOrSelfUriPermissionModeFlags(context,
documentUri);
context.grantUriPermission(getCallingPackage(), newDocumentUri, modeFlags);
@@ -694,8 +699,8 @@
*/
public final void revokeDocumentPermission(String documentId) {
final Context context = getContext();
- context.revokeUriPermission(DocumentsContract.buildDocumentUri(mAuthority, documentId), ~0);
- context.revokeUriPermission(DocumentsContract.buildViaUri(mAuthority, documentId), ~0);
+ context.revokeUriPermission(buildDocumentUri(mAuthority, documentId), ~0);
+ context.revokeUriPermission(buildTreeDocumentUri(mAuthority, documentId), ~0);
}
/**
@@ -705,7 +710,7 @@
*/
@Override
public final ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
- enforceVia(uri);
+ enforceTree(uri);
return openDocument(getDocumentId(uri), mode, null);
}
@@ -717,7 +722,7 @@
@Override
public final ParcelFileDescriptor openFile(Uri uri, String mode, CancellationSignal signal)
throws FileNotFoundException {
- enforceVia(uri);
+ enforceTree(uri);
return openDocument(getDocumentId(uri), mode, signal);
}
@@ -730,7 +735,7 @@
@SuppressWarnings("resource")
public final AssetFileDescriptor openAssetFile(Uri uri, String mode)
throws FileNotFoundException {
- enforceVia(uri);
+ enforceTree(uri);
final ParcelFileDescriptor fd = openDocument(getDocumentId(uri), mode, null);
return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null;
}
@@ -744,7 +749,7 @@
@SuppressWarnings("resource")
public final AssetFileDescriptor openAssetFile(Uri uri, String mode, CancellationSignal signal)
throws FileNotFoundException {
- enforceVia(uri);
+ enforceTree(uri);
final ParcelFileDescriptor fd = openDocument(getDocumentId(uri), mode, signal);
return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null;
}
@@ -757,7 +762,7 @@
@Override
public final AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts)
throws FileNotFoundException {
- enforceVia(uri);
+ enforceTree(uri);
if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) {
final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE);
return openDocumentThumbnail(getDocumentId(uri), sizeHint, null);
@@ -775,7 +780,7 @@
public final AssetFileDescriptor openTypedAssetFile(
Uri uri, String mimeTypeFilter, Bundle opts, CancellationSignal signal)
throws FileNotFoundException {
- enforceVia(uri);
+ enforceTree(uri);
if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) {
final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE);
return openDocumentThumbnail(getDocumentId(uri), sizeHint, signal);
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index cfab1b3..0fe764f 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -1886,6 +1886,9 @@
* The MIME type for entries in this table.
*/
public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/radio";
+
+ // Not instantiable.
+ private Radio() { }
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bec401e..06c05ee 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -791,6 +791,15 @@
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_PAIRING_SETTINGS = "android.settings.PAIRING_SETTINGS";
+ /**
+ * Activity Action: Show battery saver settings.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_BATTERY_SAVER_SETTINGS
+ = "android.settings.BATTERY_SAVER_SETTINGS";
+
// End of Intent actions for Settings
/**
@@ -4528,6 +4537,12 @@
public static final String SMS_DEFAULT_APPLICATION = "sms_default_application";
/**
+ * Specifies the package name currently configured to be the primary phone application
+ * @hide
+ */
+ public static final String PHONE_DEFAULT_APPLICATION = "phone_default_application";
+
+ /**
* Name of a package that the current user has explicitly allowed to see all of that
* user's notifications.
*
@@ -4567,6 +4582,16 @@
public static final String DISPLAY_INTERCEPTED_NOTIFICATIONS = "display_intercepted_notifications";
/**
+ * If enabled, apps should try to skip any introductory hints on first launch. This might
+ * apply to users that are already familiar with the environment or temporary users, like
+ * guests.
+ * <p>
+ * Type : int (0 to show hints, 1 to skip showing hints)
+ * @hide
+ */
+ public static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -6024,6 +6049,13 @@
*/
public static final String LOW_POWER_MODE = "low_power";
+ /**
+ * Battery level [1-99] at which low power mode automatically turns on.
+ * If 0, it will not automatically turn on.
+ * @hide
+ */
+ public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
+
/**
* If 1, the activity manager will aggressively finish activities and
* processes as soon as they are no longer needed. If 0, the normal
@@ -6200,6 +6232,14 @@
public static final String DEVICE_NAME = "device_name";
/**
+ * Whether it should be possible to create a guest user on the device.
+ * <p>
+ * Type: int (0 for disabled, 1 for enabled)
+ * @hide
+ */
+ public static final String GUEST_USER_ENABLED = "guest_user_enabled";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
@@ -6513,6 +6553,53 @@
public static boolean putFloat(ContentResolver cr, String name, float value) {
return putString(cr, name, Float.toString(value));
}
+
+
+ /**
+ * Subscription to be used for voice call on a multi sim device. The supported values
+ * are 0 = SUB1, 1 = SUB2 and etc.
+ * @hide
+ */
+ public static final String MULTI_SIM_VOICE_CALL_SUBSCRIPTION = "multi_sim_voice_call";
+
+ /**
+ * Used to provide option to user to select subscription during dial.
+ * The supported values are 0 = disable or 1 = enable prompt.
+ * @hide
+ */
+ public static final String MULTI_SIM_VOICE_PROMPT = "multi_sim_voice_prompt";
+
+ /**
+ * Subscription to be used for data call on a multi sim device. The supported values
+ * are 0 = SUB1, 1 = SUB2 and etc.
+ * @hide
+ */
+ public static final String MULTI_SIM_DATA_CALL_SUBSCRIPTION = "multi_sim_data_call";
+
+ /**
+ * Subscription to be used for SMS on a multi sim device. The supported values
+ * are 0 = SUB1, 1 = SUB2 and etc.
+ * @hide
+ */
+ public static final String MULTI_SIM_SMS_SUBSCRIPTION = "multi_sim_sms";
+
+ /**
+ * Used to provide option to user to select subscription during send SMS.
+ * The value 1 - enable, 0 - disable
+ * @hide
+ */
+ public static final String MULTI_SIM_SMS_PROMPT = "multi_sim_sms_prompt";
+
+
+
+ /** User preferred subscriptions setting.
+ * This holds the details of the user selected subscription from the card and
+ * the activation status. Each settings string have the coma separated values
+ * iccId,appType,appId,activationStatus,3gppIndex,3gpp2Index
+ * @hide
+ */
+ public static final String[] MULTI_SIM_USER_PREFERRED_SUBS = {"user_preferred_sub1",
+ "user_preferred_sub2","user_preferred_sub3"};
}
/**
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java
index 2fcec52..b6137d1 100644
--- a/core/java/android/service/fingerprint/FingerprintManager.java
+++ b/core/java/android/service/fingerprint/FingerprintManager.java
@@ -22,12 +22,14 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
+import android.util.Slog;
/**
* A class that coordinates access to the fingerprint hardware.
@@ -36,31 +38,40 @@
public class FingerprintManager {
private static final String TAG = "FingerprintManager";
private static final boolean DEBUG = true;
- private static final String FINGERPRINT_SERVICE_PACKAGE = "com.android.service.fingerprint";
- private static final String FINGERPRINT_SERVICE_CLASS =
- "com.android.service.fingerprint.FingerprintService";
private static final int MSG_ENROLL_RESULT = 100;
- private static final int MSG_SCANNED = 101;
- private static final int MSG_ERROR = 102;
- private static final int MSG_REMOVED = 103;
+ private static final int MSG_ACQUIRED = 101;
+ private static final int MSG_PROCESSED = 102;
+ 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;
- public static final int FINGERPRINT_ERROR = -1; // One of the error messages below.
- // Progress messages.
- public static final int FINGERPRINT_SCANNED = 1;
- public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2;
+ // Message types. Must agree with HAL (fingerprint.h)
+ public static final int FINGERPRINT_ERROR = -1;
+ public static final int FINGERPRINT_ACQUIRED = 1;
+ public static final int FINGERPRINT_PROCESSED = 2;
+ public static final int FINGERPRINT_TEMPLATE_ENROLLING = 3;
public static final int FINGERPRINT_TEMPLATE_REMOVED = 4;
- // Error messages. Must agree with fingerprint HAL definitions.
+ // Error messages. Must agree with HAL (fingerprint.h)
public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
- public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2;
+ 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;
+ // FINGERPRINT_ACQUIRED 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;
+
private IFingerprintService mService;
private FingerprintManagerReceiver mClientReceiver;
private Context mContext;
+ private IBinder mToken = new Binder();
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
@@ -69,8 +80,11 @@
case MSG_ENROLL_RESULT:
mClientReceiver.onEnrollResult(msg.arg1, msg.arg2);
break;
- case MSG_SCANNED:
- mClientReceiver.onScanned(msg.arg1, msg.arg2);
+ case MSG_ACQUIRED:
+ mClientReceiver.onAcquired(msg.arg1);
+ break;
+ case MSG_PROCESSED:
+ mClientReceiver.onProcessed(msg.arg1);
break;
case MSG_ERROR:
mClientReceiver.onError(msg.arg1);
@@ -82,45 +96,26 @@
}
};
- public FingerprintManager(Context context) {
+ public FingerprintManager(Context context, IFingerprintService service) {
mContext = context;
- // Connect to service...
- Intent intent = new Intent();
- intent.setClassName(FINGERPRINT_SERVICE_PACKAGE, FINGERPRINT_SERVICE_CLASS);
- if (!context.bindServiceAsUser(intent, mFingerprintConnection,
- Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF)) {
- if (DEBUG) Log.v(TAG, "Can't bind to " + FINGERPRINT_SERVICE_CLASS);
+ mService = service;
+ if (mService == null) {
+ Slog.v(TAG, "FingerprintManagerService was null");
}
}
- private final ServiceConnection mFingerprintConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG) Log.v(TAG, "Connected to FingerprintService");
- mService = IFingerprintService.Stub.asInterface(service);
- try {
- mService.startListening(mServiceReceiver, getCurrentUserId());
- } catch (RemoteException e) {
- if (DEBUG) Log.v(TAG, "Failed to set callback", e);
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) Log.v(TAG, "Disconnected from FingerprintService");
- mService = null;
- }
- };
-
private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
public void onEnrollResult(int fingerprintId, int remaining) {
mHandler.obtainMessage(MSG_ENROLL_RESULT, fingerprintId, remaining).sendToTarget();
}
- public void onScanned(int fingerprintId, int confidence) {
- mHandler.obtainMessage(MSG_SCANNED, fingerprintId, confidence)
- .sendToTarget();;
+ public void onAcquired(int acquireInfo) {
+ mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0).sendToTarget();
+ }
+
+ public void onProcessed(int fingerprintId) {
+ mHandler.obtainMessage(MSG_PROCESSED, fingerprintId, 0).sendToTarget();
}
public void onError(int error) {
@@ -151,12 +146,14 @@
*/
public void enroll(long timeout) {
if (mServiceReceiver == null) {
- throw new IllegalStateException("enroll: Call registerCallback() first");
+ sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
+ return;
}
if (mService != null) try {
- mService.enroll(timeout, getCurrentUserId());
+ mService.enroll(mToken, timeout, getCurrentUserId());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception while enrolling: ", e);
+ sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
}
}
@@ -166,10 +163,19 @@
* @param fingerprintId
*/
public void remove(int fingerprintId) {
- if (mService != null) try {
- mService.remove(fingerprintId, getCurrentUserId());
- } catch (RemoteException e) {
- Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
+ 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);
}
}
@@ -181,10 +187,13 @@
mClientReceiver = receiver;
if (mService != null) {
try {
- mService.startListening(mServiceReceiver, getCurrentUserId());
+ mService.startListening(mToken, mServiceReceiver, getCurrentUserId());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception in startListening(): ", e);
}
+ } else {
+ Log.w(TAG, "startListening(): Service not connected!");
+ sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
}
}
@@ -201,15 +210,38 @@
* Stops the client from listening to fingerprint events.
*/
public void stopListening() {
- mClientReceiver = null;
if (mService != null) {
try {
- mService.stopListening(getCurrentUserId());
+ mService.stopListening(mToken, getCurrentUserId());
+ mClientReceiver = null;
} catch (RemoteException e) {
Log.v(TAG, "Remote exception in stopListening(): ", e);
}
} else {
Log.w(TAG, "stopListening(): Service not connected!");
+ sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
}
}
+
+ public void enrollCancel() {
+ if (mServiceReceiver == null) {
+ sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
+ return;
+ }
+ 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);
+ }
+ } else {
+ Log.w(TAG, "enrollCancel(): Service not connected!");
+ }
+ }
+
+ private void sendError(int msg, int arg1, int arg2) {
+ mHandler.obtainMessage(msg, arg1, arg2);
+ }
}
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
index 34f1655..e5193f5 100644
--- a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
+++ b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
@@ -30,18 +30,32 @@
public void onEnrollResult(int fingerprintId, int remaining) { }
/**
- * Fingerprint scan detected. Most clients will use this function to detect a fingerprint
+ * 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 fingerprintId is the finger the hardware has detected.
- * @param confidence from 0 (no confidence) to 65535 (high confidence). Fingerprint 0 has
- * special meaning - the finger wasn't recognized.
+ * @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 onScanned(int fingerprintId, int confidence) { }
+ 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_BAD_CAPTURE} or
+ * {@link FingerprintManager#FINGERPRINT_ERROR_UNABLE_TO_PROCESS} or
* {@link FingerprintManager#FINGERPRINT_ERROR_TIMEOUT}
* {@link FingerprintManager#FINGERPRINT_ERROR_NO_SPACE}
*
diff --git a/core/java/android/service/fingerprint/FingerprintService.java b/core/java/android/service/fingerprint/FingerprintService.java
deleted file mode 100644
index c7fa7cd..0000000
--- a/core/java/android/service/fingerprint/FingerprintService.java
+++ /dev/null
@@ -1,219 +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.service.fingerprint;
-
-import android.app.Service;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.util.Slog;
-
-import java.io.PrintWriter;
-import java.util.HashMap;
-
-/**
- * A service to manage multiple clients that want to access the fingerprint HAL API.
- * The service is responsible for maintaining a list of clients and dispatching all
- * fingerprint -related events.
- *
- * @hide
- */
-public class FingerprintService extends Service {
- private final String TAG = FingerprintService.class.getSimpleName() +
- "[" + getClass().getSimpleName() + "]";
- private static final boolean DEBUG = true;
- HashMap<IFingerprintServiceReceiver, ClientData> mClients =
- new HashMap<IFingerprintServiceReceiver, ClientData>();
-
- private static final int MSG_NOTIFY = 10;
-
- 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);
- break;
-
- default:
- Slog.w(TAG, "Unknown message:" + msg.what);
- }
- }
- };
-
- private static final int STATE_IDLE = 0;
- private static final int STATE_LISTENING = 1;
- private static final int STATE_ENROLLING = 2;
- private static final int STATE_DELETING = 3;
- private static final long MS_PER_SEC = 1000;
-
- private static final class ClientData {
- public IFingerprintServiceReceiver receiver;
- int state;
- int userId;
- }
-
- @Override
- public final IBinder onBind(Intent intent) {
- if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
- return new FingerprintServiceWrapper();
- }
-
- // JNI methods to communicate from FingerprintManagerService to HAL
- native int nativeEnroll(int timeout);
- native int nativeRemove(int fingerprintId);
-
- // 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 handleNotify(int msg, int arg1, int arg2) {
- for (int i = 0; i < mClients.size(); i++) {
- ClientData clientData = mClients.get(i);
- switch (msg) {
- case FingerprintManager.FINGERPRINT_ERROR: {
- if (clientData.state != STATE_IDLE) {
- // FINGERPRINT_ERROR_HW_UNAVAILABLE
- // FINGERPRINT_ERROR_BAD_CAPTURE
- // FINGERPRINT_ERROR_TIMEOUT
- // FINGERPRINT_ERROR_NO_SPACE
- final int error = arg1;
- clientData.state = STATE_IDLE;
- if (clientData.receiver != null) {
- try {
- clientData.receiver.onError(error);
- } catch (RemoteException e) {
- Slog.e(TAG, "can't send message to client. Did it die?", e);
- }
- }
- }
- }
- break;
- case FingerprintManager.FINGERPRINT_SCANNED: {
- final int fingerId = arg1;
- final int confidence = arg2;
- if (clientData.state == STATE_LISTENING && clientData.receiver != null) {
- try {
- clientData.receiver.onScanned(fingerId, confidence);
- } catch (RemoteException e) {
- Slog.e(TAG, "can't send message to client. Did it die?", e);
- }
- }
- break;
- }
- case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
- if (clientData.state == STATE_ENROLLING) {
- final int fingerId = arg1;
- final int remaining = arg2;
- if (remaining == 0) {
- FingerprintUtils.addFingerprintIdForUser(fingerId,
- getContentResolver(), clientData.userId);
- clientData.state = STATE_IDLE; // Nothing left to do
- }
- if (clientData.receiver != null) {
- try {
- clientData.receiver.onEnrollResult(fingerId, remaining);
- } catch (RemoteException e) {
- Slog.e(TAG, "can't send message to client. Did it die?", e);
- }
- }
- }
- break;
- }
- case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
- int fingerId = arg1;
- if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
- if (clientData.state == STATE_DELETING) {
- FingerprintUtils.removeFingerprintIdForUser(fingerId, getContentResolver(),
- clientData.userId);
- if (clientData.receiver != null) {
- try {
- clientData.receiver.onRemoved(fingerId);
- } catch (RemoteException e) {
- Slog.e(TAG, "can't send message to client. Did it die?", e);
- }
- }
- }
- }
- break;
- }
- }
- }
-
- int enroll(IFingerprintServiceReceiver receiver, long timeout, int userId) {
- ClientData clientData = mClients.get(receiver);
- if (clientData != null) {
- if (clientData.userId != userId) throw new IllegalStateException("Bad user");
- clientData.state = STATE_ENROLLING;
- return nativeEnroll((int) (timeout / MS_PER_SEC));
- }
- return -1;
- }
-
- int remove(IFingerprintServiceReceiver receiver, int fingerId, int userId) {
- ClientData clientData = mClients.get(receiver);
- if (clientData != null) {
- if (clientData.userId != userId) throw new IllegalStateException("Bad user");
- clientData.state = STATE_DELETING;
- // The fingerprint id will be removed when we get confirmation from the HAL
- return nativeRemove(fingerId);
- }
- return -1;
- }
-
- void startListening(IFingerprintServiceReceiver receiver, int userId) {
- ClientData clientData = new ClientData();
- clientData.state = STATE_LISTENING;
- clientData.receiver = receiver;
- clientData.userId = userId;
- mClients.put(receiver, clientData);
- }
-
- void stopListening(IFingerprintServiceReceiver receiver, int userId) {
- ClientData clientData = mClients.get(receiver);
- if (clientData != null) {
- clientData.state = STATE_IDLE;
- clientData.userId = -1;
- clientData.receiver = null;
- }
- mClients.remove(receiver);
- }
-
- private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
- IFingerprintServiceReceiver mReceiver;
- public int enroll(long timeout, int userId) {
- return mReceiver != null ? FingerprintService.this.enroll(mReceiver, timeout, userId)
- : FingerprintManager.FINGERPRINT_ERROR_NO_RECEIVER;
- }
-
- public int remove(int fingerprintId, int userId) {
- return FingerprintService.this.remove(mReceiver, fingerprintId, userId);
- }
-
- public void startListening(IFingerprintServiceReceiver receiver, int userId) {
- mReceiver = receiver;
- FingerprintService.this.startListening(receiver, userId);
- }
-
- public void stopListening(int userId) {
- FingerprintService.this.stopListening(mReceiver, userId);
- }
- }
-}
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/service/fingerprint/FingerprintUtils.java
index 81a2aac..f4b5526 100644
--- a/core/java/android/service/fingerprint/FingerprintUtils.java
+++ b/core/java/android/service/fingerprint/FingerprintUtils.java
@@ -18,10 +18,12 @@
import android.content.ContentResolver;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Log;
import java.util.Arrays;
+public
class FingerprintUtils {
private static final boolean DEBUG = true;
private static final String TAG = "FingerprintUtils";
@@ -30,13 +32,16 @@
String fingerIdsRaw = Settings.Secure.getStringForUser(res,
Settings.Secure.USER_FINGERPRINT_IDS, userId);
- String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
- int result[] = new int[fingerStringIds.length];
- for (int i = 0; i < result.length; i++) {
- try {
- result[i] = Integer.decode(fingerStringIds[i]);
- } catch (NumberFormatException e) {
- if (DEBUG) Log.d(TAG, "Error when parsing finger id " + fingerStringIds[i]);
+ int result[] = {};
+ if (!TextUtils.isEmpty(fingerIdsRaw)) {
+ String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
+ result = new int[fingerStringIds.length];
+ for (int i = 0; i < result.length; i++) {
+ try {
+ result[i] = Integer.decode(fingerStringIds[i]);
+ } catch (NumberFormatException e) {
+ if (DEBUG) Log.d(TAG, "Error when parsing finger id " + fingerStringIds[i]);
+ }
}
}
return result;
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/service/fingerprint/IFingerprintService.aidl
index e92c20c..43d5e9a 100644
--- a/core/java/android/service/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintService.aidl
@@ -22,17 +22,20 @@
* Communication channel from client to the fingerprint service.
* @hide
*/
-interface IFingerprintService {
- // Returns 0 if successfully started, -1 otherwise
- int enroll(long timeout, int userId);
+oneway interface IFingerprintService {
+ // Any errors resulting from this call will be returned to the listener
+ void enroll(IBinder token, long timeout, int userId);
+
+ // Any errors resulting from this call will be returned to the listener
+ void enrollCancel(IBinder token, int userId);
- // Returns 0 if fingerprintId's template can be removed, -1 otherwise
- int remove(int fingerprintId, int userId);
+ // Any errors resulting from this call will be returned to the listener
+ void remove(IBinder token, int fingerprintId, int userId);
// Start listening for fingerprint events. This has the side effect of starting
// the hardware if not already started.
- oneway void startListening(IFingerprintServiceReceiver receiver, int userId);
+ void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId);
// Stops listening for fingerprints
- oneway void stopListening(int userId);
+ void stopListening(IBinder token, int userId);
}
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
index 4826b59..af4128f 100644
--- a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
@@ -24,7 +24,8 @@
*/
oneway interface IFingerprintServiceReceiver {
void onEnrollResult(int fingerprintId, int remaining);
- void onScanned(int fingerprintId, int confidence);
+ void onAcquired(int acquiredInfo);
+ void onProcessed(int fingerprintId);
void onError(int error);
void onRemoved(int fingerprintId);
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 557f5a6..8bd0f4d 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -16,7 +16,7 @@
package android.service.notification;
-import android.annotation.PrivateApi;
+import android.annotation.SystemApi;
import android.annotation.SdkConstant;
import android.app.INotificationManager;
import android.app.Service;
@@ -29,6 +29,7 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.ArrayMap;
import android.util.Log;
import java.util.List;
@@ -54,7 +55,7 @@
+ "[" + getClass().getSimpleName() + "]";
private INotificationListenerWrapper mWrapper = null;
- private Ranking mRanking;
+ private RankingMap mRankingMap;
private INotificationManager mNoMan;
@@ -75,7 +76,22 @@
* object as well as its identifying information (tag and id) and source
* (package name).
*/
- public abstract void onNotificationPosted(StatusBarNotification sbn);
+ public void onNotificationPosted(StatusBarNotification sbn) {
+ // optional
+ }
+
+ /**
+ * Implement this method to learn about new notifications as they are posted by apps.
+ *
+ * @param sbn A data structure encapsulating the original {@link android.app.Notification}
+ * object as well as its identifying information (tag and id) and source
+ * (package name).
+ * @param rankingMap The current ranking map that can be used to retrieve ranking information
+ * for active notifications, including the newly posted one.
+ */
+ public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
+ onNotificationPosted(sbn);
+ }
/**
* Implement this method to learn when notifications are removed.
@@ -94,7 +110,33 @@
* and source (package name) used to post the {@link android.app.Notification} that
* was just removed.
*/
- public abstract void onNotificationRemoved(StatusBarNotification sbn);
+ public void onNotificationRemoved(StatusBarNotification sbn) {
+ // optional
+ }
+
+ /**
+ * Implement this method to learn when notifications are removed.
+ * <P>
+ * This might occur because the user has dismissed the notification using system UI (or another
+ * notification listener) or because the app has withdrawn the notification.
+ * <P>
+ * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the
+ * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight
+ * fields such as {@link android.app.Notification#contentView} and
+ * {@link android.app.Notification#largeIcon}. However, all other fields on
+ * {@link StatusBarNotification}, sufficient to match this call with a prior call to
+ * {@link #onNotificationPosted(StatusBarNotification)}, will be intact.
+ *
+ * @param sbn A data structure encapsulating at least the original information (tag and id)
+ * and source (package name) used to post the {@link android.app.Notification} that
+ * was just removed.
+ * @param rankingMap The current ranking map that can be used to retrieve ranking information
+ * for active notifications.
+ *
+ */
+ public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
+ onNotificationRemoved(sbn);
+ }
/**
* Implement this method to learn about when the listener is enabled and connected to
@@ -107,10 +149,11 @@
/**
* Implement this method to be notified when the notification ranking changes.
- * <P>
- * Call {@link #getCurrentRanking()} to retrieve the new ranking.
+ *
+ * @param rankingMap The current ranking map that can be used to retrieve ranking information
+ * for active notifications.
*/
- public void onNotificationRankingUpdate() {
+ public void onNotificationRankingUpdate(RankingMap rankingMap) {
// optional
}
@@ -241,16 +284,19 @@
*
* <p>
* The returned object represents the current ranking snapshot and only
- * applies for currently active notifications. Hence you must retrieve a
- * new Ranking after each notification event such as
- * {@link #onNotificationPosted(StatusBarNotification)},
- * {@link #onNotificationRemoved(StatusBarNotification)}, etc.
+ * applies for currently active notifications.
+ * <p>
+ * Generally you should use the RankingMap that is passed with events such
+ * as {@link #onNotificationPosted(StatusBarNotification, RankingMap)},
+ * {@link #onNotificationRemoved(StatusBarNotification, RankingMap)}, and
+ * so on. This method should only be used when needing access outside of
+ * such events, for example to retrieve the RankingMap right after
+ * initialization.
*
- * @return A {@link NotificationListenerService.Ranking} object providing
- * access to ranking information
+ * @return A {@link RankingMap} object providing access to ranking information
*/
- public Ranking getCurrentRanking() {
- return mRanking;
+ public RankingMap getCurrentRanking() {
+ return mRankingMap;
}
@Override
@@ -279,7 +325,7 @@
* @param currentUser the user to use as the stream filter
* @hide
*/
- @PrivateApi
+ @SystemApi
public void registerAsSystemService(ComponentName componentName, int currentUser)
throws RemoteException {
if (mWrapper == null) {
@@ -297,7 +343,7 @@
* with (@link registerAsService).
* @hide
*/
- @PrivateApi
+ @SystemApi
public void unregisterAsSystemService() throws RemoteException {
if (mWrapper != null) {
INotificationManager noMan = getNotificationInterface();
@@ -313,7 +359,7 @@
synchronized (mWrapper) {
applyUpdate(update);
try {
- NotificationListenerService.this.onNotificationPosted(sbn);
+ NotificationListenerService.this.onNotificationPosted(sbn, mRankingMap);
} catch (Throwable t) {
Log.w(TAG, "Error running onNotificationPosted", t);
}
@@ -326,7 +372,7 @@
synchronized (mWrapper) {
applyUpdate(update);
try {
- NotificationListenerService.this.onNotificationRemoved(sbn);
+ NotificationListenerService.this.onNotificationRemoved(sbn, mRankingMap);
} catch (Throwable t) {
Log.w(TAG, "Error running onNotificationRemoved", t);
}
@@ -351,7 +397,7 @@
synchronized (mWrapper) {
applyUpdate(update);
try {
- NotificationListenerService.this.onNotificationRankingUpdate();
+ NotificationListenerService.this.onNotificationRankingUpdate(mRankingMap);
} catch (Throwable t) {
Log.w(TAG, "Error running onNotificationRankingUpdate", t);
}
@@ -360,7 +406,65 @@
}
private void applyUpdate(NotificationRankingUpdate update) {
- mRanking = new Ranking(update);
+ mRankingMap = new RankingMap(update);
+ }
+
+ /**
+ * Provides access to ranking information on a currently active
+ * notification.
+ *
+ * <p>
+ * Note that this object is not updated on notification events (such as
+ * {@link #onNotificationPosted(StatusBarNotification, RankingMap)},
+ * {@link #onNotificationRemoved(StatusBarNotification)}, etc.). Make sure
+ * to retrieve a new Ranking from the current {@link RankingMap} whenever
+ * a notification event occurs.
+ */
+ public static class Ranking {
+ private final String mKey;
+ private final int mRank;
+ private final boolean mIsAmbient;
+ private final boolean mIsInterceptedByDnd;
+
+ private Ranking(String key, int rank, boolean isAmbient, boolean isInterceptedByDnd) {
+ mKey = key;
+ mRank = rank;
+ mIsAmbient = isAmbient;
+ mIsInterceptedByDnd = isInterceptedByDnd;
+ }
+
+ /**
+ * Returns the key of the notification this Ranking applies to.
+ */
+ public String getKey() {
+ return mKey;
+ }
+
+ /**
+ * Returns the rank of the notification.
+ *
+ * @return the rank of the notification, that is the 0-based index in
+ * the list of active notifications.
+ */
+ public int getRank() {
+ return mRank;
+ }
+
+ /**
+ * Returns whether the notification is an ambient notification, that is
+ * a notification that doesn't require the user's immediate attention.
+ */
+ public boolean isAmbient() {
+ return mIsAmbient;
+ }
+
+ /**
+ * Returns whether the notification was intercepted by
+ * "Do not disturb".
+ */
+ public boolean isInterceptedByDoNotDisturb() {
+ return mIsInterceptedByDnd;
+ }
}
/**
@@ -371,11 +475,14 @@
* Note that this object represents a ranking snapshot that only applies to
* notifications active at the time of retrieval.
*/
- public static class Ranking implements Parcelable {
+ public static class RankingMap implements Parcelable {
private final NotificationRankingUpdate mRankingUpdate;
+ private final ArrayMap<String, Ranking> mRankingCache;
+ private boolean mRankingCacheInitialized;
- private Ranking(NotificationRankingUpdate rankingUpdate) {
+ private RankingMap(NotificationRankingUpdate rankingUpdate) {
mRankingUpdate = rankingUpdate;
+ mRankingCache = new ArrayMap<>(rankingUpdate.getOrderedKeys().length);
}
/**
@@ -389,56 +496,37 @@
}
/**
- * Returns the rank of the notification with the given key, that is the
- * index of <code>key</code> in the array of keys returned by
- * {@link #getOrderedKeys()}.
+ * Returns the Ranking for the notification with the given key.
*
- * @return The rank of the notification with the given key; -1 when the
- * given key is unknown.
+ * @return the Ranking of the notification with the given key;
+ * <code>null</code> when the key is unknown.
*/
- public int getRank(String key) {
- // TODO: Optimize.
+ public Ranking getRanking(String key) {
+ synchronized (mRankingCache) {
+ if (!mRankingCacheInitialized) {
+ initializeRankingCache();
+ mRankingCacheInitialized = true;
+ }
+ }
+ return mRankingCache.get(key);
+ }
+
+ private void initializeRankingCache() {
String[] orderedKeys = mRankingUpdate.getOrderedKeys();
- for (int i = 0; i < orderedKeys.length; i++) {
- if (orderedKeys[i].equals(key)) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Returns whether the notification with the given key was intercepted
- * by "Do not disturb".
- */
- public boolean isInterceptedByDoNotDisturb(String key) {
- // TODO: Optimize.
- for (String interceptedKey : mRankingUpdate.getDndInterceptedKeys()) {
- if (interceptedKey.equals(key)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns whether the notification with the given key is an ambient
- * notification, that is a notification that doesn't require the user's
- * immediate attention.
- */
- public boolean isAmbient(String key) {
- // TODO: Optimize.
int firstAmbientIndex = mRankingUpdate.getFirstAmbientIndex();
- if (firstAmbientIndex < 0) {
- return false;
- }
- String[] orderedKeys = mRankingUpdate.getOrderedKeys();
- for (int i = firstAmbientIndex; i < orderedKeys.length; i++) {
- if (orderedKeys[i].equals(key)) {
- return true;
+ for (int i = 0; i < orderedKeys.length; i++) {
+ String key = orderedKeys[i];
+ boolean isAmbient = firstAmbientIndex > -1 && firstAmbientIndex <= i;
+ boolean isInterceptedByDnd = false;
+ // TODO: Optimize.
+ for (String s : mRankingUpdate.getDndInterceptedKeys()) {
+ if (s.equals(key)) {
+ isInterceptedByDnd = true;
+ break;
+ }
}
+ mRankingCache.put(key, new Ranking(key, i, isAmbient, isInterceptedByDnd));
}
- return false;
}
// ----------- Parcelable
@@ -453,16 +541,16 @@
dest.writeParcelable(mRankingUpdate, flags);
}
- public static final Creator<Ranking> CREATOR = new Creator<Ranking>() {
+ public static final Creator<RankingMap> CREATOR = new Creator<RankingMap>() {
@Override
- public Ranking createFromParcel(Parcel source) {
+ public RankingMap createFromParcel(Parcel source) {
NotificationRankingUpdate rankingUpdate = source.readParcelable(null);
- return new Ranking(rankingUpdate);
+ return new RankingMap(rankingUpdate);
}
@Override
- public Ranking[] newArray(int size) {
- return new Ranking[size];
+ public RankingMap[] newArray(int size) {
+ return new RankingMap[size];
}
};
}
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index a6cddae..8fa45e6 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -80,6 +80,11 @@
private ITrustAgentServiceCallback mCallback;
+ private Runnable mPendingGrantTrustTask;
+
+ // Lock used to access mPendingGrantTrustTask and mCallback.
+ private final Object mLock = new Object();
+
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
@@ -127,12 +132,24 @@
* @param initiatedByUser indicates that the user has explicitly initiated an action that proves
* the user is about to use the device.
*/
- public final void grantTrust(CharSequence message, long durationMs, boolean initiatedByUser) {
- if (mCallback != null) {
- try {
- mCallback.grantTrust(message.toString(), durationMs, initiatedByUser);
- } catch (RemoteException e) {
- onError("calling enableTrust()");
+ public final void grantTrust(
+ final CharSequence message, final long durationMs, final boolean initiatedByUser) {
+ synchronized (mLock) {
+ if (mCallback != null) {
+ try {
+ mCallback.grantTrust(message.toString(), durationMs, initiatedByUser);
+ } catch (RemoteException e) {
+ onError("calling enableTrust()");
+ }
+ } else {
+ // Remember trust has been granted so we can effectively grant it once the service
+ // is bound.
+ mPendingGrantTrustTask = new Runnable() {
+ @Override
+ public void run() {
+ grantTrust(message, durationMs, initiatedByUser);
+ }
+ };
}
}
}
@@ -141,11 +158,16 @@
* Call to revoke trust on the device.
*/
public final void revokeTrust() {
- if (mCallback != null) {
- try {
- mCallback.revokeTrust();
- } catch (RemoteException e) {
- onError("calling revokeTrust()");
+ synchronized (mLock) {
+ if (mPendingGrantTrustTask != null) {
+ mPendingGrantTrustTask = null;
+ }
+ if (mCallback != null) {
+ try {
+ mCallback.revokeTrust();
+ } catch (RemoteException e) {
+ onError("calling revokeTrust()");
+ }
}
}
}
@@ -164,7 +186,13 @@
}
public void setCallback(ITrustAgentServiceCallback callback) {
- mCallback = callback;
+ synchronized (mLock) {
+ mCallback = callback;
+ if (mPendingGrantTrustTask != null) {
+ mPendingGrantTrustTask.run();
+ mPendingGrantTrustTask = null;
+ }
+ }
}
}
diff --git a/core/java/android/service/voice/DspInfo.java b/core/java/android/service/voice/DspInfo.java
new file mode 100644
index 0000000..0862309
--- /dev/null
+++ b/core/java/android/service/voice/DspInfo.java
@@ -0,0 +1,56 @@
+/*
+ * 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.service.voice;
+
+import java.util.UUID;
+
+/**
+ * Properties of the DSP hardware on the device.
+ * @hide
+ */
+public class DspInfo {
+ /**
+ * Unique voice engine Id (changes with each version).
+ */
+ public final UUID voiceEngineId;
+
+ /**
+ * Human readable voice detection engine implementor.
+ */
+ public final String voiceEngineImplementor;
+ /**
+ * Human readable voice detection engine description.
+ */
+ public final String voiceEngineDescription;
+ /**
+ * Human readable voice detection engine version
+ */
+ public final int voiceEngineVersion;
+ /**
+ * Rated power consumption when detection is active.
+ */
+ public final int powerConsumptionMw;
+
+ public DspInfo(UUID voiceEngineId, String voiceEngineImplementor,
+ String voiceEngineDescription, int version, int powerConsumptionMw) {
+ this.voiceEngineId = voiceEngineId;
+ this.voiceEngineImplementor = voiceEngineImplementor;
+ this.voiceEngineDescription = voiceEngineDescription;
+ this.voiceEngineVersion = version;
+ this.powerConsumptionMw = powerConsumptionMw;
+ }
+}
diff --git a/core/java/android/service/voice/KeyphraseEnrollmentInfo.java b/core/java/android/service/voice/KeyphraseEnrollmentInfo.java
new file mode 100644
index 0000000..ebe41ce
--- /dev/null
+++ b/core/java/android/service/voice/KeyphraseEnrollmentInfo.java
@@ -0,0 +1,246 @@
+/*
+ * 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.service.voice;
+
+import android.Manifest;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.List;
+
+/** @hide */
+public class KeyphraseEnrollmentInfo {
+ private static final String TAG = "KeyphraseEnrollmentInfo";
+ /**
+ * Name under which a Hotword enrollment component publishes information about itself.
+ * This meta-data should reference an XML resource containing a
+ * <code><{@link
+ * android.R.styleable#VoiceEnrollmentApplication
+ * voice-enrollment-application}></code> tag.
+ */
+ private static final String VOICE_KEYPHRASE_META_DATA = "android.voice_enrollment";
+ /**
+ * Activity Action: Show activity for managing the keyphrases for hotword detection.
+ * This needs to be defined by an activity that supports enrolling users for hotword/keyphrase
+ * detection.
+ */
+ public static final String ACTION_MANAGE_VOICE_KEYPHRASES =
+ "com.android.intent.action.MANAGE_VOICE_KEYPHRASES";
+ /**
+ * Intent extra: The intent extra for un-enrolling a user for a particular keyphrase.
+ */
+ public static final String EXTRA_VOICE_KEYPHRASE_UNENROLL =
+ "com.android.intent.extra.VOICE_KEYPHRASE_UNENROLL";
+ /**
+ * Intent extra: The hint text to be shown on the voice keyphrase management UI.
+ */
+ public static final String EXTRA_VOICE_KEYPHRASE_HINT_TEXT =
+ "com.android.intent.extra.VOICE_KEYPHRASE_HINT_TEXT";
+ /**
+ * Intent extra: The voice locale to use while managing the keyphrase.
+ */
+ public static final String EXTRA_VOICE_KEYPHRASE_LOCALE =
+ "com.android.intent.extra.VOICE_KEYPHRASE_LOCALE";
+
+ private KeyphraseInfo[] mKeyphrases;
+ private String mEnrollmentPackage;
+ private String mParseError;
+
+ public KeyphraseEnrollmentInfo(PackageManager pm) {
+ // Find the apps that supports enrollment for hotword keyhphrases,
+ // Pick a privileged app and obtain the information about the supported keyphrases
+ // from its metadata.
+ List<ResolveInfo> ris = pm.queryIntentActivities(
+ new Intent(ACTION_MANAGE_VOICE_KEYPHRASES), PackageManager.MATCH_DEFAULT_ONLY);
+ if (ris == null || ris.isEmpty()) {
+ // No application capable of enrolling for voice keyphrases is present.
+ mParseError = "No enrollment application found";
+ return;
+ }
+
+ boolean found = false;
+ ApplicationInfo ai = null;
+ for (ResolveInfo ri : ris) {
+ try {
+ ai = pm.getApplicationInfo(
+ ri.activityInfo.packageName, PackageManager.GET_META_DATA);
+ if ((ai.flags & ApplicationInfo.FLAG_PRIVILEGED) == 0) {
+ // The application isn't privileged (/system/priv-app).
+ // The enrollment application needs to be a privileged system app.
+ Slog.w(TAG, ai.packageName + "is not a privileged system app");
+ continue;
+ }
+ if (!Manifest.permission.MANAGE_VOICE_KEYPHRASES.equals(ai.permission)) {
+ // The application trying to manage keyphrases doesn't
+ // require the MANAGE_VOICE_KEYPHRASES permission.
+ Slog.w(TAG, ai.packageName + " does not require MANAGE_VOICE_KEYPHRASES");
+ continue;
+ }
+ mEnrollmentPackage = ai.packageName;
+ found = true;
+ break;
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "error parsing voice enrollment meta-data", e);
+ }
+ }
+
+ if (!found) {
+ mKeyphrases = null;
+ mParseError = "No suitable enrollment application found";
+ return;
+ }
+
+ XmlResourceParser parser = null;
+ try {
+ parser = ai.loadXmlMetaData(pm, VOICE_KEYPHRASE_META_DATA);
+ if (parser == null) {
+ mParseError = "No " + VOICE_KEYPHRASE_META_DATA + " meta-data for "
+ + ai.packageName;
+ return;
+ }
+
+ Resources res = pm.getResourcesForApplication(ai);
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ }
+
+ String nodeName = parser.getName();
+ if (!"voice-enrollment-application".equals(nodeName)) {
+ mParseError = "Meta-data does not start with voice-enrollment-application tag";
+ return;
+ }
+
+ TypedArray array = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.VoiceEnrollmentApplication);
+ int searchKeyphraseId = array.getInt(
+ com.android.internal.R.styleable.VoiceEnrollmentApplication_searchKeyphraseId,
+ -1);
+ if (searchKeyphraseId != -1) {
+ String searchKeyphrase = array.getString(com.android.internal.R.styleable
+ .VoiceEnrollmentApplication_searchKeyphrase);
+ String searchKeyphraseSupportedLocales =
+ array.getString(com.android.internal.R.styleable
+ .VoiceEnrollmentApplication_searchKeyphraseSupportedLocales);
+ String[] supportedLocales = new String[0];
+ // Get all the supported locales from the comma-delimted string.
+ if (searchKeyphraseSupportedLocales != null
+ && !searchKeyphraseSupportedLocales.isEmpty()) {
+ supportedLocales = searchKeyphraseSupportedLocales.split(",");
+ }
+ mKeyphrases = new KeyphraseInfo[1];
+ mKeyphrases[0] = new KeyphraseInfo(
+ searchKeyphraseId, searchKeyphrase, supportedLocales);
+ } else {
+ mParseError = "searchKeyphraseId not specified in meta-data";
+ return;
+ }
+ } catch (XmlPullParserException e) {
+ mParseError = "Error parsing keyphrase enrollment meta-data: " + e;
+ Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e);
+ return;
+ } catch (IOException e) {
+ mParseError = "Error parsing keyphrase enrollment meta-data: " + e;
+ Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e);
+ return;
+ } catch (PackageManager.NameNotFoundException e) {
+ mParseError = "Error parsing keyphrase enrollment meta-data: " + e;
+ Slog.w(TAG, "error parsing keyphrase enrollment meta-data", e);
+ return;
+ } finally {
+ if (parser != null) parser.close();
+ }
+ }
+
+ public String getParseError() {
+ return mParseError;
+ }
+
+ /**
+ * @return An array of available keyphrases that can be enrolled on the system.
+ * It may be null if no keyphrases can be enrolled.
+ */
+ public KeyphraseInfo[] getKeyphrases() {
+ return mKeyphrases;
+ }
+
+ /**
+ * Returns an intent to launch an activity that manages the given keyphrase
+ * for the locale.
+ *
+ * @param enroll Indicates if the intent should enroll the user or un-enroll them.
+ * @param keyphrase The keyphrase that the user needs to be enrolled to.
+ * @param locale The locale for which the enrollment needs to be performed.
+ * @return An {@link Intent} to manage the keyphrase. This can be null if managing the
+ * given keyphrase/locale combination isn't possible.
+ */
+ public Intent getManageKeyphraseIntent(boolean enroll, String keyphrase, String locale) {
+ if (mEnrollmentPackage == null || mEnrollmentPackage.isEmpty()) {
+ Slog.w(TAG, "No enrollment application exists");
+ return null;
+ }
+
+ if (isKeyphraseEnrollmentSupported(keyphrase, locale)) {
+ Intent intent = new Intent(ACTION_MANAGE_VOICE_KEYPHRASES)
+ .setPackage(mEnrollmentPackage)
+ .putExtra(EXTRA_VOICE_KEYPHRASE_HINT_TEXT, keyphrase)
+ .putExtra(EXTRA_VOICE_KEYPHRASE_LOCALE, locale);
+ if (!enroll) intent.putExtra(EXTRA_VOICE_KEYPHRASE_UNENROLL, true);
+ return intent;
+ }
+ return null;
+ }
+
+ /**
+ * Indicates if enrollment is supported for the given keyphrase & locale.
+ *
+ * @param keyphrase The keyphrase that the user needs to be enrolled to.
+ * @param locale The locale for which the enrollment needs to be performed.
+ * @return true, if an enrollment client supports the given keyphrase and the given locale.
+ */
+ public boolean isKeyphraseEnrollmentSupported(String keyphrase, String locale) {
+ if (mKeyphrases == null || mKeyphrases.length == 0) {
+ Slog.w(TAG, "Enrollment application doesn't support keyphrases");
+ return false;
+ }
+ for (KeyphraseInfo keyphraseInfo : mKeyphrases) {
+ // Check if the given keyphrase is supported in the locale provided by
+ // the enrollment application.
+ String supportedKeyphrase = keyphraseInfo.keyphrase;
+ if (supportedKeyphrase.equalsIgnoreCase(keyphrase)
+ && keyphraseInfo.supportedLocales.contains(locale)) {
+ return true;
+ }
+ }
+ Slog.w(TAG, "Enrollment application doesn't support the given keyphrase");
+ return false;
+ }
+}
diff --git a/core/java/android/service/voice/KeyphraseInfo.java b/core/java/android/service/voice/KeyphraseInfo.java
new file mode 100644
index 0000000..d266e1a
--- /dev/null
+++ b/core/java/android/service/voice/KeyphraseInfo.java
@@ -0,0 +1,27 @@
+package android.service.voice;
+
+import android.util.ArraySet;
+
+/**
+ * A Voice Keyphrase.
+ * @hide
+ */
+public class KeyphraseInfo {
+ public final int id;
+ public final String keyphrase;
+ public final ArraySet<String> supportedLocales;
+
+ public KeyphraseInfo(int id, String keyphrase, String[] supportedLocales) {
+ this.id = id;
+ this.keyphrase = keyphrase;
+ this.supportedLocales = new ArraySet<String>(supportedLocales.length);
+ for (String locale : supportedLocales) {
+ this.supportedLocales.add(locale);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "id=" + id + ", keyphrase=" + keyphrase + ", supported-locales=" + supportedLocales;
+ }
+}
diff --git a/core/java/android/service/voice/SoundTriggerManager.java b/core/java/android/service/voice/SoundTriggerManager.java
new file mode 100644
index 0000000..2d049b9
--- /dev/null
+++ b/core/java/android/service/voice/SoundTriggerManager.java
@@ -0,0 +1,73 @@
+/*
+ * 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.service.voice;
+
+import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
+
+import java.util.ArrayList;
+
+/**
+ * Manager for {@link SoundTrigger} APIs.
+ * Currently this just acts as an abstraction over all SoundTrigger API calls.
+ * @hide
+ */
+public class SoundTriggerManager {
+ /** The {@link DspInfo} for the system, or null if none exists. */
+ public DspInfo dspInfo;
+
+ public SoundTriggerManager() {
+ ArrayList <ModuleProperties> modules = new ArrayList<>();
+ int status = SoundTrigger.listModules(modules);
+ if (status != SoundTrigger.STATUS_OK || modules.size() == 0) {
+ // TODO(sansid, elaurent): Figure out how to handle errors in listing the modules here.
+ dspInfo = null;
+ } else {
+ // TODO(sansid, elaurent): Figure out how to determine which module corresponds to the
+ // DSP hardware.
+ ModuleProperties properties = modules.get(0);
+ dspInfo = new DspInfo(properties.uuid, properties.implementor, properties.description,
+ properties.version, properties.powerConsumptionMw);
+ }
+ }
+
+ /**
+ * @return True, if the keyphrase is supported on DSP for the given locale.
+ */
+ public boolean isKeyphraseSupported(String keyphrase, String locale) {
+ // TODO(sansid): We also need to look into a SoundTrigger API that let's us
+ // query this. For now just return supported if there's a DSP available.
+ return dspInfo != null;
+ }
+
+ /**
+ * @return True, if the keyphrase is has been enrolled for the given locale.
+ */
+ public boolean isKeyphraseEnrolled(String keyphrase, String locale) {
+ // TODO(sansid, elaurent): Query SoundTrigger to list currently loaded sound models.
+ // They have been enrolled.
+ return false;
+ }
+
+ /**
+ * @return True, if a recognition for the keyphrase is active for the given locale.
+ */
+ public boolean isKeyphraseActive(String keyphrase, String locale) {
+ // TODO(sansid, elaurent): Check if the recognition for the keyphrase is currently active.
+ return false;
+ }
+}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index e15489b..e0329f8 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -17,7 +17,6 @@
package android.service.voice;
import android.annotation.SdkConstant;
-import android.app.Instrumentation;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
@@ -25,8 +24,11 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractionManagerService;
+
/**
* Top-level service of the current global voice interactor, which is providing
* support for hotwording, the back-end of a {@link android.app.VoiceInteractor}, etc.
@@ -51,6 +53,16 @@
public static final String SERVICE_INTERFACE =
"android.service.voice.VoiceInteractionService";
+ // TODO(sansid): Unhide these.
+ /** @hide */
+ public static final int KEYPHRASE_UNAVAILABLE = 0;
+ /** @hide */
+ public static final int KEYPHRASE_UNENROLLED = 1;
+ /** @hide */
+ public static final int KEYPHRASE_ENROLLED = 2;
+ /** @hide */
+ public static final int KEYPHRASE_ACTIVE = 3;
+
/**
* Name under which a VoiceInteractionService component publishes information about itself.
* This meta-data should reference an XML resource containing a
@@ -64,6 +76,9 @@
IVoiceInteractionManagerService mSystemService;
+ private SoundTriggerManager mSoundTriggerManager;
+ private KeyphraseEnrollmentInfo mKeyphraseEnrollmentInfo;
+
public void startSession(Bundle args) {
try {
mSystemService.startSession(mInterface, args);
@@ -76,6 +91,8 @@
super.onCreate();
mSystemService = IVoiceInteractionManagerService.Stub.asInterface(
ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
+ mKeyphraseEnrollmentInfo = new KeyphraseEnrollmentInfo(getPackageManager());
+ mSoundTriggerManager = new SoundTriggerManager();
}
@Override
@@ -85,4 +102,44 @@
}
return null;
}
+
+ /**
+ * Gets the state of always-on hotword detection for the given keyphrase and locale
+ * on this system.
+ * Availability implies that the hardware on this system is capable of listening for
+ * the given keyphrase or not.
+ * The return code is one of {@link #KEYPHRASE_UNAVAILABLE}, {@link #KEYPHRASE_UNENROLLED}
+ * {@link #KEYPHRASE_ENROLLED} or {@link #KEYPHRASE_ACTIVE}.
+ *
+ * @param keyphrase The keyphrase whose availability is being checked.
+ * @param locale The locale for which the availability is being checked.
+ * @return Indicates if always-on hotword detection is available for the given keyphrase.
+ * TODO(sansid): Unhide this.
+ * @hide
+ */
+ public final int getAlwaysOnKeyphraseAvailability(String keyphrase, String locale) {
+ // The available keyphrases is a combination of DSP availability and
+ // the keyphrases that have an enrollment application for them.
+ if (!mSoundTriggerManager.isKeyphraseSupported(keyphrase, locale)
+ || !mKeyphraseEnrollmentInfo.isKeyphraseEnrollmentSupported(keyphrase, locale)) {
+ return KEYPHRASE_UNAVAILABLE;
+ }
+ if (!mSoundTriggerManager.isKeyphraseEnrolled(keyphrase, locale)) {
+ return KEYPHRASE_UNENROLLED;
+ }
+ if (!mSoundTriggerManager.isKeyphraseActive(keyphrase, locale)) {
+ return KEYPHRASE_ENROLLED;
+ } else {
+ return KEYPHRASE_ACTIVE;
+ }
+ }
+
+ /**
+ * @return Details of keyphrases available for enrollment.
+ * @hide
+ */
+ @VisibleForTesting
+ protected final KeyphraseEnrollmentInfo getKeyphraseEnrollmentInfo() {
+ return mKeyphraseEnrollmentInfo;
+ }
}
diff --git a/core/java/android/speech/tts/RequestConfig.java b/core/java/android/speech/tts/RequestConfig.java
index 4b5385f..84880c0 100644
--- a/core/java/android/speech/tts/RequestConfig.java
+++ b/core/java/android/speech/tts/RequestConfig.java
@@ -1,3 +1,18 @@
+/*
+ * 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.speech.tts;
import android.media.AudioManager;
diff --git a/core/java/android/speech/tts/RequestConfigHelper.java b/core/java/android/speech/tts/RequestConfigHelper.java
index b25c985..bc65280 100644
--- a/core/java/android/speech/tts/RequestConfigHelper.java
+++ b/core/java/android/speech/tts/RequestConfigHelper.java
@@ -1,3 +1,18 @@
+/*
+ * 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.speech.tts;
import android.speech.tts.TextToSpeechClient.EngineStatus;
@@ -31,7 +46,8 @@
/**
* Score positively voices that exactly match the given locale
- * @param locale Reference locale. If null, the default locale will be used.
+ * @param locale Reference locale. If null, the system default locale for the
+ * current user will be used ({@link Locale#getDefault()}).
*/
public ExactLocaleMatcher(Locale locale) {
if (locale == null) {
@@ -55,7 +71,8 @@
/**
* Score positively voices with similar locale.
- * @param locale Reference locale. If null, default will be used.
+ * @param locale Reference locale. If null, the system default locale for the
+ * current user will be used ({@link Locale#getDefault()}).
*/
public LanguageMatcher(Locale locale) {
if (locale == null) {
@@ -149,10 +166,10 @@
}
/**
- * Get highest quality voice for the default locale.
+ * Get highest quality voice for the TTS default locale.
*
* Call {@link #highestQuality(EngineStatus, boolean, VoiceScorer)} with
- * {@link LanguageMatcher} set to device default locale.
+ * {@link LanguageMatcher} set to the {@link EngineStatus#getDefaultLocale()}.
*
* @param engineStatus
* Voices status received from a {@link TextToSpeechClient#getEngineStatus()} call.
@@ -164,7 +181,7 @@
public static RequestConfig highestQuality(EngineStatus engineStatus,
boolean hasToBeEmbedded) {
return highestQuality(engineStatus, hasToBeEmbedded,
- new LanguageMatcher(Locale.getDefault()));
+ new LanguageMatcher(engineStatus.getDefaultLocale()));
}
}
diff --git a/core/java/android/speech/tts/SynthesisRequestV2.java b/core/java/android/speech/tts/SynthesisRequestV2.java
index 130e3f9..938458c9 100644
--- a/core/java/android/speech/tts/SynthesisRequestV2.java
+++ b/core/java/android/speech/tts/SynthesisRequestV2.java
@@ -1,3 +1,18 @@
+/*
+ * 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.speech.tts;
import android.os.Bundle;
@@ -152,9 +167,7 @@
}
};
- /**
- * @hide
- */
+ /** @hide */
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/speech/tts/TextToSpeechClient.java b/core/java/android/speech/tts/TextToSpeechClient.java
index 0c0be83..f726743 100644
--- a/core/java/android/speech/tts/TextToSpeechClient.java
+++ b/core/java/android/speech/tts/TextToSpeechClient.java
@@ -42,6 +42,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -357,9 +358,13 @@
/** Name of the TTS engine package */
private final String mPackageName;
- private EngineStatus(String packageName, List<VoiceInfo> voices) {
+ /** Engine default locale */
+ private final Locale mDefaultLocale;
+
+ private EngineStatus(String packageName, List<VoiceInfo> voices, Locale defaultLocale) {
this.mVoices = Collections.unmodifiableList(voices);
this.mPackageName = packageName;
+ this.mDefaultLocale = defaultLocale;
}
/**
@@ -375,6 +380,16 @@
public String getEnginePackage() {
return mPackageName;
}
+
+ /**
+ * Get the default locale to use for TTS with this TTS engine.
+ * Unless the user changed the TTS settings for this engine, the value returned should be
+ * the same as the system default locale for the current user
+ * ({@link Locale#getDefault()}).
+ */
+ public Locale getDefaultLocale() {
+ return mDefaultLocale;
+ }
}
/** Unique synthesis request identifier. */
@@ -638,7 +653,9 @@
return null;
}
- return new EngineStatus(mServiceConnection.getEngineName(), voices);
+ return new EngineStatus(mServiceConnection.getEngineName(), voices,
+ mEnginesHelper.getLocalePrefForEngine(
+ mServiceConnection.getEngineName()));
}
private class Connection implements ServiceConnection {
@@ -696,7 +713,9 @@
public void onVoicesInfoChange(List<VoiceInfo> voicesInfo) {
synchronized (mLock) {
mEngineStatus = new EngineStatus(mServiceConnection.getEngineName(),
- voicesInfo);
+ voicesInfo,
+ mEnginesHelper.getLocalePrefForEngine(
+ mServiceConnection.getEngineName()));
mMainHandler.obtainMessage(InternalHandler.WHAT_ENGINE_STATUS_CHANGED,
mEngineStatus).sendToTarget();
}
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 14a4024..20f3ad7 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -460,8 +460,8 @@
}
private String[] getSettingsLocale() {
- final String locale = mEngineHelper.getLocalePrefForEngine(mPackageName);
- return TtsEngines.parseLocalePref(locale);
+ final Locale locale = mEngineHelper.getLocalePrefForEngine(mPackageName);
+ return TtsEngines.toOldLocaleStringFormat(locale);
}
private int getSecureSettingInt(String name, int defaultValue) {
diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java
index 9b929a3..7474efe 100644
--- a/core/java/android/speech/tts/TtsEngines.java
+++ b/core/java/android/speech/tts/TtsEngines.java
@@ -28,6 +28,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+
import static android.provider.Settings.Secure.getString;
import android.provider.Settings;
@@ -42,8 +43,10 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.MissingResourceException;
/**
@@ -53,16 +56,52 @@
* Comments in this class the use the shorthand "system engines" for engines that
* are a part of the system image.
*
+ * This class is thread-safe/
+ *
* @hide
*/
public class TtsEngines {
private static final String TAG = "TtsEngines";
private static final boolean DBG = false;
- private static final String LOCALE_DELIMITER = "-";
+ /** Locale delimiter used by the old-style 3 char locale string format (like "eng-usa") */
+ private static final String LOCALE_DELIMITER_OLD = "-";
+
+ /** Locale delimiter used by the new-style locale string format (Locale.toString() results,
+ * like "en_US") */
+ private static final String LOCALE_DELIMITER_NEW = "_";
private final Context mContext;
+ /** Mapping of various language strings to the normalized Locale form */
+ private static final Map<String, String> sNormalizeLanguage;
+
+ /** Mapping of various country strings to the normalized Locale form */
+ private static final Map<String, String> sNormalizeCountry;
+
+ // Populate the sNormalize* maps
+ static {
+ HashMap<String, String> normalizeLanguage = new HashMap<String, String>();
+ for (String language : Locale.getISOLanguages()) {
+ try {
+ normalizeLanguage.put(new Locale(language).getISO3Language(), language);
+ } catch (MissingResourceException e) {
+ continue;
+ }
+ }
+ sNormalizeLanguage = Collections.unmodifiableMap(normalizeLanguage);
+
+ HashMap<String, String> normalizeCountry = new HashMap<String, String>();
+ for (String country : Locale.getISOCountries()) {
+ try {
+ normalizeCountry.put(new Locale("", country).getISO3Country(), country);
+ } catch (MissingResourceException e) {
+ continue;
+ }
+ }
+ sNormalizeCountry = Collections.unmodifiableMap(normalizeCountry);
+ }
+
public TtsEngines(Context ctx) {
mContext = ctx;
}
@@ -282,139 +321,139 @@
}
/**
- * Returns the locale string for a given TTS engine. Attempts to read the
+ * Returns the default locale for a given TTS engine. Attempts to read the
* value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}, failing which the
- * old style value from {@link Settings.Secure#TTS_DEFAULT_LANG} is read. If
- * both these values are empty, the default phone locale is returned.
+ * default phone locale is returned.
*
* @param engineName the engine to return the locale for.
- * @return the locale string preference for this engine. Will be non null
- * and non empty.
+ * @return the locale preference for this engine. Will be non null.
*/
- public String getLocalePrefForEngine(String engineName) {
- String locale = parseEnginePrefFromList(
- getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE),
- engineName);
-
- if (TextUtils.isEmpty(locale)) {
- // The new style setting is unset, attempt to return the old style setting.
- locale = getV1Locale();
- }
-
- if (DBG) Log.d(TAG, "getLocalePrefForEngine(" + engineName + ")= " + locale);
-
- return locale;
+ public Locale getLocalePrefForEngine(String engineName) {
+ return getLocalePrefForEngine(engineName,
+ getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE));
}
/**
+ * Returns the default locale for a given TTS engine from given settings string. */
+ public Locale getLocalePrefForEngine(String engineName, String prefValue) {
+ String localeString = parseEnginePrefFromList(
+ prefValue,
+ engineName);
+
+ if (TextUtils.isEmpty(localeString)) {
+ // The new style setting is unset, attempt to return the old style setting.
+ return Locale.getDefault();
+ }
+
+ Locale result = parseLocaleString(localeString);
+ if (result == null) {
+ Log.w(TAG, "Failed to parse locale " + localeString + ", returning en_US instead");
+ result = Locale.US;
+ }
+
+ if (DBG) Log.d(TAG, "getLocalePrefForEngine(" + engineName + ")= " + result);
+
+ return result;
+ }
+
+
+ /**
* True if a given TTS engine uses the default phone locale as a default locale. Attempts to
- * read the value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}, failing which the
- * old style value from {@link Settings.Secure#TTS_DEFAULT_LANG} is read. If
- * both these values are empty, this methods returns true.
+ * read the value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}. If
+ * its value is empty, this methods returns true.
*
* @param engineName the engine to return the locale for.
*/
public boolean isLocaleSetToDefaultForEngine(String engineName) {
- return (TextUtils.isEmpty(parseEnginePrefFromList(
+ return TextUtils.isEmpty(parseEnginePrefFromList(
getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE),
- engineName)) &&
- TextUtils.isEmpty(
- Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.TTS_DEFAULT_LANG)));
+ engineName));
}
-
/**
- * Parses a locale preference value delimited by {@link #LOCALE_DELIMITER}.
- * Varies from {@link String#split} in that it will always return an array
- * of length 3 with non null values.
+ * Parses a locale encoded as a string, and tries its best to return a valid {@link Locale}
+ * object, even if the input string is encoded using the old-style 3 character format e.g.
+ * "deu-deu". At the end, we test if the resulting locale can return ISO3 language and
+ * country codes ({@link Locale#getISO3Language()} and {@link Locale#getISO3Country()}),
+ * if it fails to do so, we return null.
*/
- public static String[] parseLocalePref(String pref) {
- String[] returnVal = new String[] { "", "", ""};
- if (!TextUtils.isEmpty(pref)) {
- String[] split = pref.split(LOCALE_DELIMITER);
- System.arraycopy(split, 0, returnVal, 0, split.length);
+ public Locale parseLocaleString(String localeString) {
+ String language = "", country = "", variant = "";
+ if (!TextUtils.isEmpty(localeString)) {
+ String[] split = localeString.split(
+ "[" + LOCALE_DELIMITER_OLD + LOCALE_DELIMITER_NEW + "]");
+ language = split[0].toLowerCase();
+ if (split.length == 0) {
+ Log.w(TAG, "Failed to convert " + localeString + " to a valid Locale object. Only" +
+ " separators");
+ return null;
+ }
+ if (split.length > 3) {
+ Log.w(TAG, "Failed to convert " + localeString + " to a valid Locale object. Too" +
+ " many separators");
+ return null;
+ }
+ if (split.length >= 2) {
+ country = split[1].toUpperCase();
+ }
+ if (split.length >= 3) {
+ variant = split[2];
+ }
+
}
- if (DBG) Log.d(TAG, "parseLocalePref(" + returnVal[0] + "," + returnVal[1] +
- "," + returnVal[2] +")");
+ String normalizedLanguage = sNormalizeLanguage.get(language);
+ if (normalizedLanguage != null) {
+ language = normalizedLanguage;
+ }
- return returnVal;
+ String normalizedCountry= sNormalizeCountry.get(country);
+ if (normalizedCountry != null) {
+ country = normalizedCountry;
+ }
+
+ if (DBG) Log.d(TAG, "parseLocalePref(" + language + "," + country +
+ "," + variant +")");
+
+ Locale result = new Locale(language, country, variant);
+ try {
+ result.getISO3Language();
+ result.getISO3Country();
+ return result;
+ } catch(MissingResourceException e) {
+ Log.w(TAG, "Failed to convert " + localeString + " to a valid Locale object.");
+ return null;
+ }
}
/**
- * @return the old style locale string constructed from
- * {@link Settings.Secure#TTS_DEFAULT_LANG},
- * {@link Settings.Secure#TTS_DEFAULT_COUNTRY} and
- * {@link Settings.Secure#TTS_DEFAULT_VARIANT}. If no such locale is set,
- * then return the default phone locale.
- */
- private String getV1Locale() {
- final ContentResolver cr = mContext.getContentResolver();
-
- final String lang = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_LANG);
- final String country = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_COUNTRY);
- final String variant = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_VARIANT);
-
- if (TextUtils.isEmpty(lang)) {
- return getDefaultLocale();
- }
-
- String v1Locale = lang;
- if (!TextUtils.isEmpty(country)) {
- v1Locale += LOCALE_DELIMITER + country;
- } else {
- return v1Locale;
- }
-
- if (!TextUtils.isEmpty(variant)) {
- v1Locale += LOCALE_DELIMITER + variant;
- }
-
- return v1Locale;
- }
-
- /**
- * Return the default device locale in form of 3 letter codes delimited by
- * {@link #LOCALE_DELIMITER}:
+ * Return the old-style string form of the locale. It consists of 3 letter codes:
* <ul>
- * <li> "ISO 639-2/T language code" if locale have no country entry</li>
- * <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country code "
- * if locale have no variant entry</li>
- * <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country code
- * {@link #LOCALE_DELIMITER} variant" if locale have variant entry</li>
+ * <li>"ISO 639-2/T language code" if the locale has no country entry</li>
+ * <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country code"
+ * if the locale has no variant entry</li>
+ * <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country
+ * code{@link #LOCALE_DELIMITER}variant" if the locale has a variant entry</li>
* </ul>
+ * If we fail to generate those codes using {@link Locale#getISO3Country()} and
+ * {@link Locale#getISO3Language()}, then we return new String[]{"eng","USA",""};
*/
- public String getDefaultLocale() {
- final Locale locale = Locale.getDefault();
-
+ static public String[] toOldLocaleStringFormat(Locale locale) {
+ String[] ret = new String[]{"","",""};
try {
// Note that the default locale might have an empty variant
// or language, and we take care that the construction is
// the same as {@link #getV1Locale} i.e no trailing delimiters
// or spaces.
- String defaultLocale = locale.getISO3Language();
- if (TextUtils.isEmpty(defaultLocale)) {
- Log.w(TAG, "Default locale is empty.");
- return "";
- }
+ ret[0] = locale.getISO3Language();
+ ret[1] = locale.getISO3Country();
+ ret[2] = locale.getVariant();
- if (!TextUtils.isEmpty(locale.getISO3Country())) {
- defaultLocale += LOCALE_DELIMITER + locale.getISO3Country();
- } else {
- // Do not allow locales of the form lang--variant with
- // an empty country.
- return defaultLocale;
- }
- if (!TextUtils.isEmpty(locale.getVariant())) {
- defaultLocale += LOCALE_DELIMITER + locale.getVariant();
- }
-
- return defaultLocale;
+ return ret;
} catch (MissingResourceException e) {
// Default locale does not have a ISO 3166 and/or ISO 639-2/T codes. Return the
// default "eng-usa" (that would be the result of Locale.getDefault() == Locale.US).
- return "eng-usa";
+ return new String[]{"eng","USA",""};
}
}
@@ -443,16 +482,21 @@
return null;
}
- public synchronized void updateLocalePrefForEngine(String name, String newLocale) {
+ /**
+ * Serialize the locale to a string and store it as a default locale for the given engine. If
+ * the passed locale is null, an empty string will be serialized; that empty string, when
+ * read back, will evaluate to {@link Locale#getDefault()}.
+ */
+ public synchronized void updateLocalePrefForEngine(String engineName, Locale newLocale) {
final String prefList = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.TTS_DEFAULT_LOCALE);
if (DBG) {
- Log.d(TAG, "updateLocalePrefForEngine(" + name + ", " + newLocale +
+ Log.d(TAG, "updateLocalePrefForEngine(" + engineName + ", " + newLocale +
"), originally: " + prefList);
}
final String newPrefList = updateValueInCommaSeparatedList(prefList,
- name, newLocale);
+ engineName, (newLocale != null) ? newLocale.toString() : "");
if (DBG) Log.d(TAG, "updateLocalePrefForEngine(), writing: " + newPrefList.toString());
diff --git a/core/java/android/speech/tts/VoiceInfo.java b/core/java/android/speech/tts/VoiceInfo.java
index 16b9a97..71629dc 100644
--- a/core/java/android/speech/tts/VoiceInfo.java
+++ b/core/java/android/speech/tts/VoiceInfo.java
@@ -1,3 +1,18 @@
+/*
+ * 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.speech.tts;
import android.os.Bundle;
diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java
index d426d124..8674c66 100644
--- a/core/java/android/text/GraphicsOperations.java
+++ b/core/java/android/text/GraphicsOperations.java
@@ -38,7 +38,7 @@
* {@hide}
*/
void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
- float x, float y, int flags, Paint p);
+ float x, float y, boolean isRtl, Paint p);
/**
* Just like {@link Paint#measureText}.
@@ -55,12 +55,12 @@
* @hide
*/
float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
- int flags, float[] advances, int advancesIndex, Paint paint);
+ boolean isRtl, float[] advances, int advancesIndex, Paint paint);
/**
* Just like {@link Paint#getTextRunCursor}.
* @hide
*/
- int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
+ int getTextRunCursor(int contextStart, int contextEnd, int dir, int offset,
int cursorOpt, Paint p);
}
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index f8e3c83..2415b11 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -159,18 +159,17 @@
mPos = p + len;
if (mEasy) {
- int flags = mDir == Layout.DIR_LEFT_TO_RIGHT
- ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
- return paint.getTextRunAdvances(mChars, p, len, p, len, flags, mWidths, p);
+ boolean isRtl = mDir != Layout.DIR_LEFT_TO_RIGHT;
+ return paint.getTextRunAdvances(mChars, p, len, p, len, isRtl, mWidths, p);
}
float totalAdvance = 0;
int level = mLevels[p];
for (int q = p, i = p + 1, e = p + len;; ++i) {
if (i == e || mLevels[i] != level) {
- int flags = (level & 0x1) == 0 ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
+ boolean isRtl = (level & 0x1) != 0;
totalAdvance +=
- paint.getTextRunAdvances(mChars, q, i - q, q, i - q, flags, mWidths, q);
+ paint.getTextRunAdvances(mChars, q, i - q, q, i - q, isRtl, mWidths, q);
if (i == e) {
break;
}
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index f440853..6b984d6 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -440,26 +440,10 @@
}
// Documentation from interface
- public SpannableStringBuilder replace(int start, int end,
+ public SpannableStringBuilder replace(final int start, final int end,
CharSequence tb, int tbstart, int tbend) {
checkRange("replace", start, end);
- // Sanity check
- if (start > end) {
- Log.w(TAG, "Bad arguments to #replace : "
- + "start = " + start + ", end = " + end);
- final int tmp = start;
- start = end;
- end = tmp;
- }
- if (tbstart > tbend) {
- Log.w(TAG, "Bad arguments to #replace : "
- + "tbstart = " + tbstart + ", tbend = " + tbend);
- final int tmp = tbstart;
- tbstart = tbend;
- tbend = tmp;
- }
-
int filtercount = mFilters.length;
for (int i = 0; i < filtercount; i++) {
CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end);
@@ -519,7 +503,7 @@
// Span watchers need to be called after text watchers, which may update the layout
sendToSpanWatchers(start, end, newLen - origLen);
- return this;
+ return this;
}
private static boolean hasNonExclusiveExclusiveSpanAt(CharSequence text, int offset) {
@@ -761,7 +745,7 @@
}
}
- return 0;
+ return 0;
}
/**
@@ -1133,20 +1117,20 @@
* {@hide}
*/
public void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd,
- float x, float y, int flags, Paint p) {
+ float x, float y, boolean isRtl, Paint p) {
checkRange("drawTextRun", start, end);
int contextLen = contextEnd - contextStart;
int len = end - start;
if (contextEnd <= mGapStart) {
- c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, flags, p);
+ c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, isRtl, p);
} else if (contextStart >= mGapStart) {
c.drawTextRun(mText, start + mGapLength, len, contextStart + mGapLength,
- contextLen, x, y, flags, p);
+ contextLen, x, y, isRtl, p);
} else {
char[] buf = TextUtils.obtain(contextLen);
getChars(contextStart, contextEnd, buf, 0);
- c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, flags, p);
+ c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, isRtl, p);
TextUtils.recycle(buf);
}
}
@@ -1203,7 +1187,7 @@
* Don't call this yourself -- exists for Paint to use internally.
* {@hide}
*/
- public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, int flags,
+ public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, boolean isRtl,
float[] advances, int advancesPos, Paint p) {
float ret;
@@ -1213,15 +1197,15 @@
if (end <= mGapStart) {
ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen,
- flags, advances, advancesPos);
+ isRtl, advances, advancesPos);
} else if (start >= mGapStart) {
ret = p.getTextRunAdvances(mText, start + mGapLength, len,
- contextStart + mGapLength, contextLen, flags, advances, advancesPos);
+ contextStart + mGapLength, contextLen, isRtl, advances, advancesPos);
} else {
char[] buf = TextUtils.obtain(contextLen);
getChars(contextStart, contextEnd, buf, 0);
ret = p.getTextRunAdvances(buf, start - contextStart, len,
- 0, contextLen, flags, advances, advancesPos);
+ 0, contextLen, isRtl, advances, advancesPos);
TextUtils.recycle(buf);
}
@@ -1244,7 +1228,7 @@
*
* @param contextStart the start index of the context
* @param contextEnd the (non-inclusive) end index of the context
- * @param flags either DIRECTION_RTL or DIRECTION_LTR
+ * @param dir either DIRECTION_RTL or DIRECTION_LTR
* @param offset the cursor position to move from
* @param cursorOpt how to move the cursor, one of CURSOR_AFTER,
* CURSOR_AT_OR_AFTER, CURSOR_BEFORE,
@@ -1254,7 +1238,7 @@
* @deprecated This is an internal method, refrain from using it in your code
*/
@Deprecated
- public int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
+ public int getTextRunCursor(int contextStart, int contextEnd, int dir, int offset,
int cursorOpt, Paint p) {
int ret;
@@ -1262,15 +1246,15 @@
int contextLen = contextEnd - contextStart;
if (contextEnd <= mGapStart) {
ret = p.getTextRunCursor(mText, contextStart, contextLen,
- flags, offset, cursorOpt);
+ dir, offset, cursorOpt);
} else if (contextStart >= mGapStart) {
ret = p.getTextRunCursor(mText, contextStart + mGapLength, contextLen,
- flags, offset + mGapLength, cursorOpt) - mGapLength;
+ dir, offset + mGapLength, cursorOpt) - mGapLength;
} else {
char[] buf = TextUtils.obtain(contextLen);
getChars(contextStart, contextEnd, buf, 0);
ret = p.getTextRunCursor(buf, 0, contextLen,
- flags, offset - contextStart, cursorOpt) + contextStart;
+ dir, offset - contextStart, cursorOpt) + contextStart;
TextUtils.recycle(buf);
}
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index d892f19..c19cf32 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -664,14 +664,14 @@
}
}
- int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
+ int dir = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
int cursorOpt = after ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE;
if (mCharsValid) {
return wp.getTextRunCursor(mChars, spanStart, spanLimit - spanStart,
- flags, offset, cursorOpt);
+ dir, offset, cursorOpt);
} else {
return wp.getTextRunCursor(mText, mStart + spanStart,
- mStart + spanLimit, flags, mStart + offset, cursorOpt) - mStart;
+ mStart + spanLimit, dir, mStart + offset, cursorOpt) - mStart;
}
}
@@ -738,15 +738,14 @@
int contextLen = contextEnd - contextStart;
if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
- int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
if (mCharsValid) {
ret = wp.getTextRunAdvances(mChars, start, runLen,
- contextStart, contextLen, flags, null, 0);
+ contextStart, contextLen, runIsRtl, null, 0);
} else {
int delta = mStart;
ret = wp.getTextRunAdvances(mText, delta + start,
delta + end, delta + contextStart, delta + contextEnd,
- flags, null, 0);
+ runIsRtl, null, 0);
}
}
@@ -977,16 +976,15 @@
private void drawTextRun(Canvas c, TextPaint wp, int start, int end,
int contextStart, int contextEnd, boolean runIsRtl, float x, int y) {
- int flags = runIsRtl ? Canvas.DIRECTION_RTL : Canvas.DIRECTION_LTR;
if (mCharsValid) {
int count = end - start;
int contextCount = contextEnd - contextStart;
c.drawTextRun(mChars, start, count, contextStart, contextCount,
- x, y, flags, wp);
+ x, y, runIsRtl, wp);
} else {
int delta = mStart;
c.drawTextRun(mText, delta + start, delta + end,
- delta + contextStart, delta + contextEnd, x, y, flags, wp);
+ delta + contextStart, delta + contextEnd, x, y, runIsRtl, wp);
}
}
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index d1f35dd..9fec9a1 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -195,7 +195,7 @@
* @return a string pattern suitable for use with {@link java.text.SimpleDateFormat}.
*/
public static String getBestDateTimePattern(Locale locale, String skeleton) {
- return ICU.getBestDateTimePattern(skeleton, locale.toString());
+ return ICU.getBestDateTimePattern(skeleton, locale);
}
/**
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index deb138d..c1341e1 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -465,32 +465,39 @@
String address;
int base = 0;
- while ((address = WebView.findAddress(string)) != null) {
- int start = string.indexOf(address);
+ try {
+ while ((address = WebView.findAddress(string)) != null) {
+ int start = string.indexOf(address);
- if (start < 0) {
- break;
+ if (start < 0) {
+ break;
+ }
+
+ LinkSpec spec = new LinkSpec();
+ int length = address.length();
+ int end = start + length;
+
+ spec.start = base + start;
+ spec.end = base + end;
+ string = string.substring(end);
+ base += end;
+
+ String encodedAddress = null;
+
+ try {
+ encodedAddress = URLEncoder.encode(address,"UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ continue;
+ }
+
+ spec.url = "geo:0,0?q=" + encodedAddress;
+ links.add(spec);
}
-
- LinkSpec spec = new LinkSpec();
- int length = address.length();
- int end = start + length;
-
- spec.start = base + start;
- spec.end = base + end;
- string = string.substring(end);
- base += end;
-
- String encodedAddress = null;
-
- try {
- encodedAddress = URLEncoder.encode(address,"UTF-8");
- } catch (UnsupportedEncodingException e) {
- continue;
- }
-
- spec.url = "geo:0,0?q=" + encodedAddress;
- links.add(spec);
+ } catch (UnsupportedOperationException e) {
+ // findAddress may fail with an unsupported exception on platforms without a WebView.
+ // In this case, we will not append anything to the links variable: it would have died
+ // in WebView.findAddress.
+ return;
}
}
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index e9c2bba..508769d 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -206,6 +206,10 @@
// like CircularPropagation
EpicenterCallback mEpicenterCallback;
+ // For Fragment shared element transitions, linking views explicitly by mismatching
+ // viewNames.
+ ArrayMap<String, String> mNameOverrides;
+
/**
* Constructs a Transition object with no target objects. A transition with
* no targets defaults to running on all target objects in the scene hierarchy
@@ -603,76 +607,76 @@
for (int i = 0; i < startValuesList.size(); ++i) {
TransitionValues start = startValuesList.get(i);
TransitionValues end = endValuesList.get(i);
- // Only bother trying to animate with values that differ between start/end
- if (start != null || end != null) {
- if (start == null || !start.equals(end)) {
- if (DBG) {
- View view = (end != null) ? end.view : start.view;
- Log.d(LOG_TAG, " differing start/end values for view " +
- view);
- if (start == null || end == null) {
- Log.d(LOG_TAG, " " + ((start == null) ?
- "start null, end non-null" : "start non-null, end null"));
- } else {
- for (String key : start.values.keySet()) {
- Object startValue = start.values.get(key);
- Object endValue = end.values.get(key);
- if (startValue != endValue && !startValue.equals(endValue)) {
- Log.d(LOG_TAG, " " + key + ": start(" + startValue +
- "), end(" + endValue +")");
- }
+ // Only bother trying to animate with valid values that differ between start/end
+ boolean isInvalidStart = start != null && !isValidTarget(start.view);
+ boolean isInvalidEnd = end != null && !isValidTarget(end.view);
+ boolean isChanged = start != end && (start == null || !start.equals(end));
+ if (isChanged && !isInvalidStart && !isInvalidEnd) {
+ if (DBG) {
+ View view = (end != null) ? end.view : start.view;
+ Log.d(LOG_TAG, " differing start/end values for view " + view);
+ if (start == null || end == null) {
+ Log.d(LOG_TAG, " " + ((start == null) ?
+ "start null, end non-null" : "start non-null, end null"));
+ } else {
+ for (String key : start.values.keySet()) {
+ Object startValue = start.values.get(key);
+ Object endValue = end.values.get(key);
+ if (startValue != endValue && !startValue.equals(endValue)) {
+ Log.d(LOG_TAG, " " + key + ": start(" + startValue +
+ "), end(" + endValue + ")");
}
}
}
- // TODO: what to do about targetIds and itemIds?
- Animator animator = createAnimator(sceneRoot, start, end);
+ }
+ // TODO: what to do about targetIds and itemIds?
+ Animator animator = createAnimator(sceneRoot, start, end);
+ if (animator != null) {
+ // Save animation info for future cancellation purposes
+ View view = null;
+ TransitionValues infoValues = null;
+ if (end != null) {
+ view = end.view;
+ String[] properties = getTransitionProperties();
+ if (view != null && properties != null && properties.length > 0) {
+ infoValues = new TransitionValues();
+ infoValues.view = view;
+ TransitionValues newValues = endValues.viewValues.get(view);
+ if (newValues != null) {
+ for (int j = 0; j < properties.length; ++j) {
+ infoValues.values.put(properties[j],
+ newValues.values.get(properties[j]));
+ }
+ }
+ int numExistingAnims = runningAnimators.size();
+ for (int j = 0; j < numExistingAnims; ++j) {
+ Animator anim = runningAnimators.keyAt(j);
+ AnimationInfo info = runningAnimators.get(anim);
+ if (info.values != null && info.view == view &&
+ ((info.name == null && getName() == null) ||
+ info.name.equals(getName()))) {
+ if (info.values.equals(infoValues)) {
+ // Favor the old animator
+ animator = null;
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ view = (start != null) ? start.view : null;
+ }
if (animator != null) {
- // Save animation info for future cancellation purposes
- View view = null;
- TransitionValues infoValues = null;
- if (end != null) {
- view = end.view;
- String[] properties = getTransitionProperties();
- if (view != null && properties != null && properties.length > 0) {
- infoValues = new TransitionValues();
- infoValues.view = view;
- TransitionValues newValues = endValues.viewValues.get(view);
- if (newValues != null) {
- for (int j = 0; j < properties.length; ++j) {
- infoValues.values.put(properties[j],
- newValues.values.get(properties[j]));
- }
- }
- int numExistingAnims = runningAnimators.size();
- for (int j = 0; j < numExistingAnims; ++j) {
- Animator anim = runningAnimators.keyAt(j);
- AnimationInfo info = runningAnimators.get(anim);
- if (info.values != null && info.view == view &&
- ((info.name == null && getName() == null) ||
- info.name.equals(getName()))) {
- if (info.values.equals(infoValues)) {
- // Favor the old animator
- animator = null;
- break;
- }
- }
- }
- }
- } else {
- view = (start != null) ? start.view : null;
+ if (mPropagation != null) {
+ long delay = mPropagation
+ .getStartDelay(sceneRoot, this, start, end);
+ startDelays.put(mAnimators.size(), delay);
+ minStartDelay = Math.min(delay, minStartDelay);
}
- if (animator != null) {
- if (mPropagation != null) {
- long delay = mPropagation
- .getStartDelay(sceneRoot, this, start, end);
- startDelays.put(mAnimators.size(), delay);
- minStartDelay = Math.min(delay, minStartDelay);
- }
- AnimationInfo info = new AnimationInfo(view, getName(),
- sceneRoot.getWindowId(), infoValues);
- runningAnimators.put(animator, info);
- mAnimators.add(animator);
- }
+ AnimationInfo info = new AnimationInfo(view, getName(),
+ sceneRoot.getWindowId(), infoValues);
+ runningAnimators.put(animator, info);
+ mAnimators.add(animator);
}
}
}
@@ -1347,6 +1351,21 @@
} else {
captureHierarchy(sceneRoot, start);
}
+ if (!start && mNameOverrides != null) {
+ int numOverrides = mNameOverrides.size();
+ ArrayList<View> overriddenViews = new ArrayList<View>(numOverrides);
+ for (int i = 0; i < numOverrides; i++) {
+ String fromName = mNameOverrides.keyAt(i);
+ overriddenViews.add(mStartValues.nameValues.remove(fromName));
+ }
+ for (int i = 0; i < numOverrides; i++) {
+ View view = overriddenViews.get(i);
+ if (view != null) {
+ String toName = mNameOverrides.valueAt(i);
+ mStartValues.nameValues.put(toName, view);
+ }
+ }
+ }
}
static void addViewValues(TransitionValuesMaps transitionValuesMaps,
@@ -1400,10 +1419,12 @@
mStartValues.viewValues.clear();
mStartValues.idValues.clear();
mStartValues.itemIdValues.clear();
+ mStartValues.nameValues.clear();
} else {
mEndValues.viewValues.clear();
mEndValues.idValues.clear();
mEndValues.itemIdValues.clear();
+ mEndValues.nameValues.clear();
}
}
@@ -1866,6 +1887,20 @@
return mCanRemoveViews;
}
+ /**
+ * Sets the shared element names -- a mapping from a name at the start state to
+ * a different name at the end state.
+ * @hide
+ */
+ public void setNameOverrides(ArrayMap<String, String> overrides) {
+ mNameOverrides = overrides;
+ }
+
+ /** @hide */
+ public ArrayMap<String, String> getNameOverrides() {
+ return mNameOverrides;
+ }
+
@Override
public String toString() {
return toString("");
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index 698b563..c04be4f 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -168,30 +168,106 @@
@Override
public TransitionSet addTarget(View target) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).addTarget(target);
+ }
return (TransitionSet) super.addTarget(target);
}
@Override
public TransitionSet addTarget(int targetId) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).addTarget(targetId);
+ }
return (TransitionSet) super.addTarget(targetId);
}
@Override
+ public TransitionSet addTarget(String targetName) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).addTarget(targetName);
+ }
+ return (TransitionSet) super.addTarget(targetName);
+ }
+
+ @Override
+ public TransitionSet addTarget(Class targetType) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).addTarget(targetType);
+ }
+ return (TransitionSet) super.addTarget(targetType);
+ }
+
+ @Override
public TransitionSet addListener(TransitionListener listener) {
return (TransitionSet) super.addListener(listener);
}
@Override
public TransitionSet removeTarget(int targetId) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).removeTarget(targetId);
+ }
return (TransitionSet) super.removeTarget(targetId);
}
@Override
public TransitionSet removeTarget(View target) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).removeTarget(target);
+ }
return (TransitionSet) super.removeTarget(target);
}
@Override
+ public TransitionSet removeTarget(Class target) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).removeTarget(target);
+ }
+ return (TransitionSet) super.removeTarget(target);
+ }
+
+ @Override
+ public TransitionSet removeTarget(String target) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).removeTarget(target);
+ }
+ return (TransitionSet) super.removeTarget(target);
+ }
+
+ @Override
+ public Transition excludeTarget(View target, boolean exclude) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).excludeTarget(target, exclude);
+ }
+ return super.excludeTarget(target, exclude);
+ }
+
+ @Override
+ public Transition excludeTarget(String targetViewName, boolean exclude) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).excludeTarget(targetViewName, exclude);
+ }
+ return super.excludeTarget(targetViewName, exclude);
+ }
+
+ @Override
+ public Transition excludeTarget(int targetId, boolean exclude) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).excludeTarget(targetId, exclude);
+ }
+ return super.excludeTarget(targetId, exclude);
+ }
+
+ @Override
+ public Transition excludeTarget(Class type, boolean exclude) {
+ for (int i = 0; i < mTransitions.size(); i++) {
+ mTransitions.get(i).excludeTarget(type, exclude);
+ }
+ return super.excludeTarget(type, exclude);
+ }
+
+ @Override
public TransitionSet removeListener(TransitionListener listener) {
return (TransitionSet) super.removeListener(listener);
}
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 0f7638b..c6c8337 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -18,6 +18,9 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
import android.view.View;
import android.view.ViewGroup;
@@ -272,15 +275,23 @@
if (startView.getParent() == null) {
// no parent - safe to use
overlayView = startView;
- } else if (startView.getParent() instanceof View &&
- startView.getParent().getParent() == null) {
+ } else if (startView.getParent() instanceof View) {
View startParent = (View) startView.getParent();
- int id = startParent.getId();
- if (id != View.NO_ID && sceneRoot.findViewById(id) != null && mCanRemoveViews) {
- // no parent, but its parent is unparented but the parent
- // hierarchy has been replaced by a new hierarchy with the same id
- // and it is safe to un-parent startView
- overlayView = startView;
+ if (!isValidTarget(startParent)) {
+ if (startView.isAttachedToWindow()) {
+ overlayView = copyViewImage(startView);
+ } else {
+ overlayView = startView;
+ }
+ } else if (startParent.getParent() == null) {
+ int id = startParent.getId();
+ if (id != View.NO_ID && sceneRoot.findViewById(id) != null
+ && mCanRemoveViews) {
+ // no parent, but its parent is unparented but the parent
+ // hierarchy has been replaced by a new hierarchy with the same id
+ // and it is safe to un-parent startView
+ overlayView = startView;
+ }
}
}
}
@@ -378,6 +389,26 @@
return null;
}
+ private View copyViewImage(View view) {
+ int width = view.getWidth();
+ int height = view.getHeight();
+ if (width <= 0 || height <= 0) {
+ return null;
+ }
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ view.draw(canvas);
+ final BitmapDrawable drawable = new BitmapDrawable(bitmap);
+
+ View overlayView = new View(view.getContext());
+ overlayView.setBackground(drawable);
+ int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
+ int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
+ overlayView.measure(widthSpec, heightSpec);
+ overlayView.layout(0, 0, width, height);
+ return overlayView;
+ }
+
/**
* The default implementation of this method returns a null Animator. Subclasses should
* override this method to make targets disappear with the desired transition. The
diff --git a/core/java/android/util/Range.java b/core/java/android/util/Range.java
index d7e8cf0..3907e77 100644
--- a/core/java/android/util/Range.java
+++ b/core/java/android/util/Range.java
@@ -97,6 +97,27 @@
}
/**
+ * Checks if the {@code value} is within the bounds of this range.
+ *
+ * <p>A value is considered to be within this range if it's {@code >=} then
+ * the lower endpoint <i>and</i> {@code <=} to the upper endpoint (using the {@link Comparable}
+ * interface.</p>
+ *
+ * @param value a non-{@code null} {@code T} reference
+ * @return {@code true} if the value is within this inclusive range, {@code false} otherwise
+ *
+ * @throws NullPointerException if {@code value} was {@code null}
+ */
+ public boolean inRange(T value) {
+ checkNotNull(value, "value must not be null");
+
+ boolean gteLower = value.compareTo(mLower) >= 0;
+ boolean lteUpper = value.compareTo(mUpper) <= 0;
+
+ return gteLower && lteUpper;
+ }
+
+ /**
* Compare two ranges for equality.
*
* <p>A range is considered equal if and only if both the lower and upper endpoints
@@ -105,16 +126,13 @@
* @return {@code true} if the ranges are equal, {@code false} otherwise
*/
@Override
- public boolean equals(final Object obj) {
+ public boolean equals(Object obj) {
if (obj == null) {
return false;
- }
- if (this == obj) {
+ } else if (this == obj) {
return true;
- }
- if (obj instanceof Range) {
+ } else if (obj instanceof Range) {
@SuppressWarnings("rawtypes")
- final
Range other = (Range) obj;
return mLower.equals(other.mLower) && mUpper.equals(other.mUpper);
}
diff --git a/core/java/android/util/Rational.java b/core/java/android/util/Rational.java
index 8d4c67f..9952859 100644
--- a/core/java/android/util/Rational.java
+++ b/core/java/android/util/Rational.java
@@ -15,29 +15,88 @@
*/
package android.util;
+import static com.android.internal.util.Preconditions.*;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+
/**
* <p>An immutable data type representation a rational number.</p>
*
* <p>Contains a pair of {@code int}s representing the numerator and denominator of a
* Rational number. </p>
*/
-public final class Rational {
+public final class Rational extends Number implements Comparable<Rational> {
+ /**
+ * Constant for the <em>Not-a-Number (NaN)</em> value of the {@code Rational} type.
+ *
+ * <p>A {@code NaN} value is considered to be equal to itself (that is {@code NaN.equals(NaN)}
+ * will return {@code true}; it is always greater than any non-{@code NaN} value (that is
+ * {@code NaN.compareTo(notNaN)} will return a number greater than {@code 0}).</p>
+ *
+ * <p>Equivalent to constructing a new rational with both the numerator and denominator
+ * equal to {@code 0}.</p>
+ */
+ public static final Rational NaN = new Rational(0, 0);
+
+ /**
+ * Constant for the positive infinity value of the {@code Rational} type.
+ *
+ * <p>Equivalent to constructing a new rational with a positive numerator and a denominator
+ * equal to {@code 0}.</p>
+ */
+ public static final Rational POSITIVE_INFINITY = new Rational(1, 0);
+
+ /**
+ * Constant for the negative infinity value of the {@code Rational} type.
+ *
+ * <p>Equivalent to constructing a new rational with a negative numerator and a denominator
+ * equal to {@code 0}.</p>
+ */
+ public static final Rational NEGATIVE_INFINITY = new Rational(-1, 0);
+
+ /**
+ * Constant for the zero value of the {@code Rational} type.
+ *
+ * <p>Equivalent to constructing a new rational with a numerator equal to {@code 0} and
+ * any non-zero denominator.</p>
+ */
+ public static final Rational ZERO = new Rational(0, 1);
+
+ /**
+ * Unique version number per class to be compliant with {@link java.io.Serializable}.
+ *
+ * <p>Increment each time the fields change in any way.</p>
+ */
+ private static final long serialVersionUID = 1L;
+
+ /*
+ * Do not change the order of these fields or add new instance fields to maintain the
+ * Serializable compatibility across API revisions.
+ */
private final int mNumerator;
private final int mDenominator;
/**
- * <p>Create a Rational with a given numerator and denominator.</p>
+ * <p>Create a {@code Rational} with a given numerator and denominator.</p>
*
* <p>The signs of the numerator and the denominator may be flipped such that the denominator
- * is always positive.</p>
+ * is always positive. Both the numerator and denominator will be converted to their reduced
+ * forms (see {@link #equals} for more details).</p>
*
- * <p>A rational value with a 0-denominator may be constructed, but will have similar semantics
- * as float {@code NaN} and {@code INF} values. For {@code NaN},
- * both {@link #getNumerator} and {@link #getDenominator} functions will return 0. For
- * positive or negative {@code INF}, only the {@link #getDenominator} will return 0.</p>
+ * <p>For example,
+ * <ul>
+ * <li>a rational of {@code 2/4} will be reduced to {@code 1/2}.
+ * <li>a rational of {@code 1/-1} will be flipped to {@code -1/1}
+ * <li>a rational of {@code 5/0} will be reduced to {@code 1/0}
+ * <li>a rational of {@code 0/5} will be reduced to {@code 0/1}
+ * </ul>
+ * </p>
*
* @param numerator the numerator of the rational
* @param denominator the denominator of the rational
+ *
+ * @see #equals
*/
public Rational(int numerator, int denominator) {
@@ -46,32 +105,100 @@
denominator = -denominator;
}
- mNumerator = numerator;
- mDenominator = denominator;
+ // Convert to reduced form
+ if (denominator == 0 && numerator > 0) {
+ mNumerator = 1; // +Inf
+ mDenominator = 0;
+ } else if (denominator == 0 && numerator < 0) {
+ mNumerator = -1; // -Inf
+ mDenominator = 0;
+ } else if (denominator == 0 && numerator == 0) {
+ mNumerator = 0; // NaN
+ mDenominator = 0;
+ } else if (numerator == 0) {
+ mNumerator = 0;
+ mDenominator = 1;
+ } else {
+ int gcd = gcd(numerator, denominator);
+
+ mNumerator = numerator / gcd;
+ mDenominator = denominator / gcd;
+ }
}
/**
* Gets the numerator of the rational.
+ *
+ * <p>The numerator will always return {@code 1} if this rational represents
+ * infinity (that is, the denominator is {@code 0}).</p>
*/
public int getNumerator() {
- if (mDenominator == 0) {
- return 0;
- }
return mNumerator;
}
/**
* Gets the denominator of the rational
+ *
+ * <p>The denominator may return {@code 0}, in which case the rational may represent
+ * positive infinity (if the numerator was positive), negative infinity (if the numerator
+ * was negative), or {@code NaN} (if the numerator was {@code 0}).</p>
+ *
+ * <p>The denominator will always return {@code 1} if the numerator is {@code 0}.
*/
public int getDenominator() {
return mDenominator;
}
- private boolean isNaN() {
+ /**
+ * Indicates whether this rational is a <em>Not-a-Number (NaN)</em> value.
+ *
+ * <p>A {@code NaN} value occurs when both the numerator and the denominator are {@code 0}.</p>
+ *
+ * @return {@code true} if this rational is a <em>Not-a-Number (NaN)</em> value;
+ * {@code false} if this is a (potentially infinite) number value
+ */
+ public boolean isNaN() {
return mDenominator == 0 && mNumerator == 0;
}
- private boolean isInf() {
+ /**
+ * Indicates whether this rational represents an infinite value.
+ *
+ * <p>An infinite value occurs when the denominator is {@code 0} (but the numerator is not).</p>
+ *
+ * @return {@code true} if this rational is a (positive or negative) infinite value;
+ * {@code false} if this is a finite number value (or {@code NaN})
+ */
+ public boolean isInfinite() {
+ return mNumerator != 0 && mDenominator == 0;
+ }
+
+ /**
+ * Indicates whether this rational represents a finite value.
+ *
+ * <p>A finite value occurs when the denominator is not {@code 0}; in other words
+ * the rational is neither infinity or {@code NaN}.</p>
+ *
+ * @return {@code true} if this rational is a (positive or negative) infinite value;
+ * {@code false} if this is a finite number value (or {@code NaN})
+ */
+ public boolean isFinite() {
+ return mDenominator != 0;
+ }
+
+ /**
+ * Indicates whether this rational represents a zero value.
+ *
+ * <p>A zero value is a {@link #isFinite finite} rational with a numerator of {@code 0}.</p>
+ *
+ * @return {@code true} if this rational is finite zero value;
+ * {@code false} otherwise
+ */
+ public boolean isZero() {
+ return isFinite() && mNumerator == 0;
+ }
+
+ private boolean isPosInf() {
return mDenominator == 0 && mNumerator > 0;
}
@@ -82,12 +209,12 @@
/**
* <p>Compare this Rational to another object and see if they are equal.</p>
*
- * <p>A Rational object can only be equal to another Rational object (comparing against any other
- * type will return false).</p>
+ * <p>A Rational object can only be equal to another Rational object (comparing against any
+ * other type will return {@code false}).</p>
*
* <p>A Rational object is considered equal to another Rational object if and only if one of
- * the following holds</p>:
- * <ul><li>Both are NaN</li>
+ * the following holds:</p>
+ * <ul><li>Both are {@code NaN}</li>
* <li>Both are infinities of the same sign</li>
* <li>Both have the same numerator and denominator in their reduced form</li>
* </ul>
@@ -96,12 +223,12 @@
* denominator by their greatest common divisor.</p>
*
* <pre>{@code
- * (new Rational(1, 2)).equals(new Rational(1, 2)) == true // trivially true
- * (new Rational(2, 3)).equals(new Rational(1, 2)) == false // trivially false
- * (new Rational(1, 2)).equals(new Rational(2, 4)) == true // true after reduction
- * (new Rational(0, 0)).equals(new Rational(0, 0)) == true // NaN.equals(NaN)
- * (new Rational(1, 0)).equals(new Rational(5, 0)) == true // both are +infinity
- * (new Rational(1, 0)).equals(new Rational(-1, 0)) == false // +infinity != -infinity
+ * (new Rational(1, 2)).equals(new Rational(1, 2)) == true // trivially true
+ * (new Rational(2, 3)).equals(new Rational(1, 2)) == false // trivially false
+ * (new Rational(1, 2)).equals(new Rational(2, 4)) == true // true after reduction
+ * (new Rational(0, 0)).equals(new Rational(0, 0)) == true // NaN.equals(NaN)
+ * (new Rational(1, 0)).equals(new Rational(5, 0)) == true // both are +infinity
+ * (new Rational(1, 0)).equals(new Rational(-1, 0)) == false // +infinity != -infinity
* }</pre>
*
* @param obj a reference to another object
@@ -110,41 +237,31 @@
*/
@Override
public boolean equals(Object obj) {
- if (obj == null) {
- return false;
- } else if (obj instanceof Rational) {
- Rational other = (Rational) obj;
- if (mDenominator == 0 || other.mDenominator == 0) {
- if (isNaN() && other.isNaN()) {
- return true;
- } else if (isInf() && other.isInf() || isNegInf() && other.isNegInf()) {
- return true;
- } else {
- return false;
- }
- } else if (mNumerator == other.mNumerator && mDenominator == other.mDenominator) {
- return true;
- } else {
- int thisGcd = gcd();
- int otherGcd = other.gcd();
-
- int thisNumerator = mNumerator / thisGcd;
- int thisDenominator = mDenominator / thisGcd;
-
- int otherNumerator = other.mNumerator / otherGcd;
- int otherDenominator = other.mDenominator / otherGcd;
-
- return (thisNumerator == otherNumerator && thisDenominator == otherDenominator);
- }
- }
- return false;
+ return obj instanceof Rational && equals((Rational) obj);
}
+ private boolean equals(Rational other) {
+ return (mNumerator == other.mNumerator && mDenominator == other.mDenominator);
+ }
+
+ /**
+ * Return a string representation of this rational, e.g. {@code "1/2"}.
+ *
+ * <p>The following rules of conversion apply:
+ * <ul>
+ * <li>{@code NaN} values will return {@code "NaN"}
+ * <li>Positive infinity values will return {@code "Infinity"}
+ * <li>Negative infinity values will return {@code "-Infinity"}
+ * <li>All other values will return {@code "numerator/denominator"} where {@code numerator}
+ * and {@code denominator} are substituted with the appropriate numerator and denominator
+ * values.
+ * </ul></p>
+ */
@Override
public String toString() {
if (isNaN()) {
return "NaN";
- } else if (isInf()) {
+ } else if (isPosInf()) {
return "Infinity";
} else if (isNegInf()) {
return "-Infinity";
@@ -160,7 +277,8 @@
* @hide
*/
public float toFloat() {
- return (float) mNumerator / (float) mDenominator;
+ // TODO: remove this duplicate function (used in CTS and the shim)
+ return floatValue();
}
/**
@@ -177,20 +295,24 @@
/**
* Calculates the greatest common divisor using Euclid's algorithm.
*
+ * <p><em>Visible for testing only.</em></p>
+ *
+ * @param numerator the numerator in a fraction
+ * @param denominator the denominator in a fraction
+ *
* @return An int value representing the gcd. Always positive.
* @hide
*/
- public int gcd() {
- /**
+ public static int gcd(int numerator, int denominator) {
+ /*
* Non-recursive implementation of Euclid's algorithm:
*
* gcd(a, 0) := a
* gcd(a, b) := gcd(b, a mod b)
*
*/
-
- int a = mNumerator;
- int b = mDenominator;
+ int a = numerator;
+ int b = denominator;
while (b != 0) {
int oldB = b;
@@ -201,4 +323,221 @@
return Math.abs(a);
}
+
+ /**
+ * Returns the value of the specified number as a {@code double}.
+ *
+ * <p>The {@code double} is calculated by converting both the numerator and denominator
+ * to a {@code double}; then returning the result of dividing the numerator by the
+ * denominator.</p>
+ *
+ * @return the divided value of the numerator and denominator as a {@code double}.
+ */
+ @Override
+ public double doubleValue() {
+ double num = mNumerator;
+ double den = mDenominator;
+
+ return num / den;
+ }
+
+ /**
+ * Returns the value of the specified number as a {@code float}.
+ *
+ * <p>The {@code float} is calculated by converting both the numerator and denominator
+ * to a {@code float}; then returning the result of dividing the numerator by the
+ * denominator.</p>
+ *
+ * @return the divided value of the numerator and denominator as a {@code float}.
+ */
+ @Override
+ public float floatValue() {
+ float num = mNumerator;
+ float den = mDenominator;
+
+ return num / den;
+ }
+
+ /**
+ * Returns the value of the specified number as a {@code int}.
+ *
+ * <p>{@link #isInfinite Finite} rationals are converted to an {@code int} value
+ * by dividing the numerator by the denominator; conversion for non-finite values happens
+ * identically to casting a floating point value to an {@code int}, in particular:
+ *
+ * <p>
+ * <ul>
+ * <li>Positive infinity saturates to the largest maximum integer
+ * {@link Integer#MAX_VALUE}</li>
+ * <li>Negative infinity saturates to the smallest maximum integer
+ * {@link Integer#MIN_VALUE}</li>
+ * <li><em>Not-A-Number (NaN)</em> returns {@code 0}.</li>
+ * </ul>
+ * </p>
+ *
+ * @return the divided value of the numerator and denominator as a {@code int}.
+ */
+ @Override
+ public int intValue() {
+ // Mimic float to int conversion rules from JLS 5.1.3
+
+ if (isPosInf()) {
+ return Integer.MAX_VALUE;
+ } else if (isNegInf()) {
+ return Integer.MIN_VALUE;
+ } else if (isNaN()) {
+ return 0;
+ } else { // finite
+ return mNumerator / mDenominator;
+ }
+ }
+
+ /**
+ * Returns the value of the specified number as a {@code long}.
+ *
+ * <p>{@link #isInfinite Finite} rationals are converted to an {@code long} value
+ * by dividing the numerator by the denominator; conversion for non-finite values happens
+ * identically to casting a floating point value to a {@code long}, in particular:
+ *
+ * <p>
+ * <ul>
+ * <li>Positive infinity saturates to the largest maximum long
+ * {@link Long#MAX_VALUE}</li>
+ * <li>Negative infinity saturates to the smallest maximum long
+ * {@link Long#MIN_VALUE}</li>
+ * <li><em>Not-A-Number (NaN)</em> returns {@code 0}.</li>
+ * </ul>
+ * </p>
+ *
+ * @return the divided value of the numerator and denominator as a {@code long}.
+ */
+ @Override
+ public long longValue() {
+ // Mimic float to long conversion rules from JLS 5.1.3
+
+ if (isPosInf()) {
+ return Long.MAX_VALUE;
+ } else if (isNegInf()) {
+ return Long.MIN_VALUE;
+ } else if (isNaN()) {
+ return 0;
+ } else { // finite
+ return mNumerator / mDenominator;
+ }
+ }
+
+ /**
+ * Returns the value of the specified number as a {@code short}.
+ *
+ * <p>{@link #isInfinite Finite} rationals are converted to a {@code short} value
+ * identically to {@link #intValue}; the {@code int} result is then truncated to a
+ * {@code short} before returning the value.</p>
+ *
+ * @return the divided value of the numerator and denominator as a {@code short}.
+ */
+ @Override
+ public short shortValue() {
+ return (short) intValue();
+ }
+
+ /**
+ * Compare this rational to the specified rational to determine their natural order.
+ *
+ * <p>{@link #NaN} is considered to be equal to itself and greater than all other
+ * {@code Rational} values. Otherwise, if the objects are not {@link #equals equal}, then
+ * the following rules apply:</p>
+ *
+ * <ul>
+ * <li>Positive infinity is greater than any other finite number (or negative infinity)
+ * <li>Negative infinity is less than any other finite number (or positive infinity)
+ * <li>The finite number represented by this rational is checked numerically
+ * against the other finite number by converting both rationals to a common denominator multiple
+ * and comparing their numerators.
+ * </ul>
+ *
+ * @param another the rational to be compared
+ *
+ * @return a negative integer, zero, or a positive integer as this object is less than,
+ * equal to, or greater than the specified rational.
+ *
+ * @throws NullPointerException if {@code another} was {@code null}
+ */
+ @Override
+ public int compareTo(Rational another) {
+ checkNotNull(another, "another must not be null");
+
+ if (equals(another)) {
+ return 0;
+ } else if (isNaN()) { // NaN is greater than the other non-NaN value
+ return 1;
+ } else if (another.isNaN()) { // the other NaN is greater than this non-NaN value
+ return -1;
+ } else if (isPosInf() || another.isNegInf()) {
+ return 1; // positive infinity is greater than any non-NaN/non-posInf value
+ } else if (isNegInf() || another.isPosInf()) {
+ return -1; // negative infinity is less than any non-NaN/non-negInf value
+ }
+
+ // else both this and another are finite numbers
+
+ // make the denominators the same, then compare numerators
+ long thisNumerator = ((long)mNumerator) * another.mDenominator; // long to avoid overflow
+ long otherNumerator = ((long)another.mNumerator) * mDenominator; // long to avoid overflow
+
+ // avoid underflow from subtraction by doing comparisons
+ if (thisNumerator < otherNumerator) {
+ return -1;
+ } else if (thisNumerator > otherNumerator) {
+ return 1;
+ } else {
+ // This should be covered by #equals, but have this code path just in case
+ return 0;
+ }
+ }
+
+ /*
+ * Serializable implementation.
+ *
+ * The following methods are omitted:
+ * >> writeObject - the default is sufficient (field by field serialization)
+ * >> readObjectNoData - the default is sufficient (0s for both fields is a NaN)
+ */
+
+ /**
+ * writeObject with default serialized form - guards against
+ * deserializing non-reduced forms of the rational.
+ *
+ * @throws InvalidObjectException if the invariants were violated
+ */
+ private void readObject(java.io.ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+
+ /*
+ * Guard against trying to deserialize illegal values (in this case, ones
+ * that don't have a standard reduced form).
+ *
+ * - Non-finite values must be one of [0, 1], [0, 0], [0, 1], [0, -1]
+ * - Finite values must always have their greatest common divisor as 1
+ */
+
+ if (mNumerator == 0) { // either zero or NaN
+ if (mDenominator == 1 || mDenominator == 0) {
+ return;
+ }
+ throw new InvalidObjectException(
+ "Rational must be deserialized from a reduced form for zero values");
+ } else if (mDenominator == 0) { // either positive or negative infinity
+ if (mNumerator == 1 || mNumerator == -1) {
+ return;
+ }
+ throw new InvalidObjectException(
+ "Rational must be deserialized from a reduced form for infinity values");
+ } else { // finite value
+ if (gcd(mNumerator, mDenominator) > 1) {
+ throw new InvalidObjectException(
+ "Rational must be deserialized from a reduced form for finite values");
+ }
+ }
+ }
}
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 8f4b710..f7d2821 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -62,10 +62,7 @@
*/
public static TimeZone getTimeZone(int offset, boolean dst, long when, String country) {
TimeZone best = null;
-
- Resources r = Resources.getSystem();
- XmlResourceParser parser = r.getXml(com.android.internal.R.xml.time_zones_by_country);
- Date d = new Date(when);
+ final Date d = new Date(when);
TimeZone current = TimeZone.getDefault();
String currentName = current.getID();
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 5056097..446bbc9 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -51,10 +51,10 @@
private int mWidth;
private int mHeight;
-
+
private float[] mPoint;
private float[] mLine;
-
+
private Rect mClipBounds;
private RectF mPathBounds;
@@ -167,7 +167,7 @@
nSetViewport(mRenderer, width, height);
}
-
+
private static native void nSetViewport(long renderer, int width, int height);
@Override
@@ -208,22 +208,22 @@
/**
* Must match Caches::FlushMode values
- *
- * @see #flushCaches(int)
+ *
+ * @see #flushCaches(int)
*/
static final int FLUSH_CACHES_LAYERS = 0;
-
+
/**
* Must match Caches::FlushMode values
- *
- * @see #flushCaches(int)
+ *
+ * @see #flushCaches(int)
*/
static final int FLUSH_CACHES_MODERATE = 1;
/**
* Must match Caches::FlushMode values
- *
- * @see #flushCaches(int)
+ *
+ * @see #flushCaches(int)
*/
static final int FLUSH_CACHES_FULL = 2;
@@ -245,7 +245,7 @@
///////////////////////////////////////////////////////////////////////////
// Hardware layer
///////////////////////////////////////////////////////////////////////////
-
+
void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
layer.setLayerPaint(paint);
nDrawLayer(mRenderer, layer.getLayer(), x, y);
@@ -298,7 +298,7 @@
public boolean clipRect(float left, float top, float right, float bottom) {
return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
}
-
+
private static native boolean nClipRect(long renderer, float left, float top,
float right, float bottom, int op);
@@ -311,14 +311,14 @@
public boolean clipRect(int left, int top, int right, int bottom) {
return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
}
-
+
private static native boolean nClipRect(long renderer, int left, int top,
int right, int bottom, int op);
@Override
public boolean clipRect(Rect rect) {
return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
- Region.Op.INTERSECT.nativeInt);
+ Region.Op.INTERSECT.nativeInt);
}
@Override
@@ -360,7 +360,7 @@
public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) {
return nQuickReject(mRenderer, left, top, right, bottom);
}
-
+
private static native boolean nQuickReject(long renderer, float left, float top,
float right, float bottom);
@@ -385,7 +385,7 @@
public void translate(float dx, float dy) {
if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy);
}
-
+
private static native void nTranslate(long renderer, float dx, float dy);
@Override
@@ -399,21 +399,24 @@
public void rotate(float degrees) {
nRotate(mRenderer, degrees);
}
-
+
private static native void nRotate(long renderer, float degrees);
@Override
public void scale(float sx, float sy) {
+ // TODO: remove
+ if (sx > 1000000 || sy > 1000000) throw new IllegalArgumentException("invalid scales passed " + sx + ", " + sy);
+
nScale(mRenderer, sx, sy);
}
-
+
private static native void nScale(long renderer, float sx, float sy);
@Override
public void setMatrix(Matrix matrix) {
nSetMatrix(mRenderer, matrix == null ? 0 : matrix.native_instance);
}
-
+
private static native void nSetMatrix(long renderer, long matrix);
@SuppressWarnings("deprecation")
@@ -421,16 +424,16 @@
public void getMatrix(Matrix matrix) {
nGetMatrix(mRenderer, matrix.native_instance);
}
-
+
private static native void nGetMatrix(long renderer, long matrix);
@Override
public void concat(Matrix matrix) {
if (matrix != null) nConcatMatrix(mRenderer, matrix.native_instance);
}
-
+
private static native void nConcatMatrix(long renderer, long matrix);
-
+
///////////////////////////////////////////////////////////////////////////
// State management
///////////////////////////////////////////////////////////////////////////
@@ -439,14 +442,14 @@
public int save() {
return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG);
}
-
+
@Override
public int save(int saveFlags) {
return nSave(mRenderer, saveFlags);
}
private static native int nSave(long renderer, int flags);
-
+
@Override
public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
if (bounds != null) {
@@ -494,12 +497,12 @@
private static native int nSaveLayerAlpha(long renderer, float left, float top, float right,
float bottom, int alpha, int saveFlags);
-
+
@Override
public void restore() {
nRestore(mRenderer);
}
-
+
private static native void nRestore(long renderer);
@Override
@@ -508,12 +511,12 @@
}
private static native void nRestoreToCount(long renderer, int saveCount);
-
+
@Override
public int getSaveCount() {
return nGetSaveCount(mRenderer);
}
-
+
private static native int nGetSaveCount(long renderer);
///////////////////////////////////////////////////////////////////////////
@@ -544,9 +547,9 @@
///////////////////////////////////////////////////////////////////////////
@Override
- public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
- Paint paint) {
- nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
+ public void drawArc(float left, float top, float right, float bottom,
+ float startAngle, float sweepAngle, boolean useCenter, Paint paint) {
+ nDrawArc(mRenderer, left, top, right, bottom,
startAngle, sweepAngle, useCenter, paint.mNativePaint);
}
@@ -739,7 +742,7 @@
public void drawColor(int color, PorterDuff.Mode mode) {
nDrawColor(mRenderer, color, mode.nativeInt);
}
-
+
private static native void nDrawColor(long renderer, int color, int mode);
@Override
@@ -771,8 +774,8 @@
}
@Override
- public void drawOval(RectF oval, Paint paint) {
- nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
+ public void drawOval(float left, float top, float right, float bottom, Paint paint) {
+ nDrawOval(mRenderer, left, top, right, bottom, paint.mNativePaint);
}
private static native void nDrawOval(long renderer, float left, float top,
@@ -930,7 +933,7 @@
nDrawText(mRenderer, text, index, count, x, y,
paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
}
-
+
private static native void nDrawText(long renderer, char[] text, int index, int count,
float x, float y, int bidiFlags, long paint, long typeface);
@@ -997,49 +1000,45 @@
@Override
public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
- float x, float y, int dir, Paint paint) {
+ float x, float y, boolean isRtl, Paint paint) {
if ((index | count | text.length - index - count) < 0) {
throw new IndexOutOfBoundsException();
}
- if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
- throw new IllegalArgumentException("Unknown direction: " + dir);
- }
- nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
+ nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, isRtl,
paint.mNativePaint, paint.mNativeTypeface);
}
private static native void nDrawTextRun(long renderer, char[] text, int index, int count,
- int contextIndex, int contextCount, float x, float y, int dir, long nativePaint, long nativeTypeface);
+ int contextIndex, int contextCount, float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
@Override
public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
- float x, float y, int dir, Paint paint) {
+ float x, float y, boolean isRtl, Paint paint) {
if ((start | end | end - start | text.length() - end) < 0) {
throw new IndexOutOfBoundsException();
}
- int flags = dir == 0 ? 0 : 1;
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
- contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
+ contextEnd, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawTextRun(this, start, end,
- contextStart, contextEnd, x, y, flags, paint);
+ contextStart, contextEnd, x, y, isRtl, paint);
} else {
int contextLen = contextEnd - contextStart;
int len = end - start;
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
- x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
+ x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
TemporaryBuffer.recycle(buf);
}
}
private static native void nDrawTextRun(long renderer, String text, int start, int end,
- int contextStart, int contextEnd, float x, float y, int flags, long nativePaint, long nativeTypeface);
+ int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
@Override
public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index b5b9199..266a6fed 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -19,7 +19,6 @@
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Paint;
-import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import com.android.internal.util.VirtualRefBasePtr;
@@ -34,34 +33,18 @@
* @hide
*/
final class HardwareLayer {
- private static final int LAYER_TYPE_TEXTURE = 1;
- private static final int LAYER_TYPE_DISPLAY_LIST = 2;
-
private HardwareRenderer mRenderer;
private VirtualRefBasePtr mFinalizer;
- private RenderNode mDisplayList;
- private final int mLayerType;
- private HardwareLayer(HardwareRenderer renderer, long deferredUpdater, int type) {
+ private HardwareLayer(HardwareRenderer renderer, long deferredUpdater) {
if (renderer == null || deferredUpdater == 0) {
throw new IllegalArgumentException("Either hardware renderer: " + renderer
+ " or deferredUpdater: " + deferredUpdater + " is invalid");
}
mRenderer = renderer;
- mLayerType = type;
mFinalizer = new VirtualRefBasePtr(deferredUpdater);
}
- private void assertType(int type) {
- if (mLayerType != type) {
- throw new IllegalAccessError("Method not appropriate for this layer type! " + mLayerType);
- }
- }
-
- boolean hasDisplayList() {
- return mDisplayList != null;
- }
-
/**
* Update the paint used when drawing this layer.
*
@@ -90,11 +73,6 @@
// Already destroyed
return;
}
-
- if (mDisplayList != null) {
- mDisplayList.destroyDisplayListData();
- mDisplayList = null;
- }
mRenderer.onLayerDestroyed(this);
mRenderer = null;
mFinalizer.release();
@@ -105,21 +83,6 @@
return mFinalizer.get();
}
- public RenderNode startRecording() {
- assertType(LAYER_TYPE_DISPLAY_LIST);
-
- if (mDisplayList == null) {
- mDisplayList = RenderNode.create("HardwareLayer");
- }
- return mDisplayList;
- }
-
- public void endRecording(Rect dirtyRect) {
- nUpdateRenderLayer(mFinalizer.get(), mDisplayList.getNativeDisplayList(),
- dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
- mRenderer.pushLayerUpdate(this);
- }
-
/**
* Copies this layer into the specified bitmap.
*
@@ -160,7 +123,6 @@
* Indicates that this layer has lost its texture.
*/
public void detachSurfaceTexture(final SurfaceTexture surface) {
- assertType(LAYER_TYPE_TEXTURE);
mRenderer.safelyRun(new Runnable() {
@Override
public void run() {
@@ -177,13 +139,11 @@
}
public void setSurfaceTexture(SurfaceTexture surface) {
- assertType(LAYER_TYPE_TEXTURE);
nSetSurfaceTexture(mFinalizer.get(), surface, false);
mRenderer.pushLayerUpdate(this);
}
public void updateSurfaceTexture() {
- assertType(LAYER_TYPE_TEXTURE);
nUpdateSurfaceTexture(mFinalizer.get());
mRenderer.pushLayerUpdate(this);
}
@@ -192,18 +152,13 @@
* This should only be used by HardwareRenderer! Do not call directly
*/
SurfaceTexture createSurfaceTexture() {
- assertType(LAYER_TYPE_TEXTURE);
SurfaceTexture st = new SurfaceTexture(nGetTexName(mFinalizer.get()));
nSetSurfaceTexture(mFinalizer.get(), st, true);
return st;
}
static HardwareLayer adoptTextureLayer(HardwareRenderer renderer, long layer) {
- return new HardwareLayer(renderer, layer, LAYER_TYPE_TEXTURE);
- }
-
- static HardwareLayer adoptDisplayListLayer(HardwareRenderer renderer, long layer) {
- return new HardwareLayer(renderer, layer, LAYER_TYPE_DISPLAY_LIST);
+ return new HardwareLayer(renderer, layer);
}
private static native void nOnTextureDestroyed(long layerUpdater);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 592dec8..c0e42a3 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -16,6 +16,7 @@
package android.view;
+import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
@@ -374,16 +375,6 @@
abstract HardwareLayer createTextureLayer();
/**
- * Creates a new hardware layer.
- *
- * @param width The minimum width of the layer
- * @param height The minimum height of the layer
- *
- * @return A hardware layer
- */
- abstract HardwareLayer createDisplayListLayer(int width, int height);
-
- /**
* Creates a new {@link SurfaceTexture} that can be used to render into the
* specified hardware layer.
*
@@ -462,10 +453,10 @@
*
* @return A hardware renderer backed by OpenGL.
*/
- static HardwareRenderer create(boolean translucent) {
+ static HardwareRenderer create(Context context, boolean translucent) {
HardwareRenderer renderer = null;
if (GLES20Canvas.isAvailable()) {
- renderer = new ThreadedRenderer(translucent);
+ renderer = new ThreadedRenderer(context, translucent);
}
return renderer;
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index c32a2c9..fa5bd88 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -46,7 +46,7 @@
int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out Rect outContentInsets);
void remove(IWindow window);
-
+
/**
* Change the parameters of a window. You supply the
* new parameters, it returns the new frame of the window on screen (the
@@ -109,7 +109,7 @@
* to optimize compositing of this part of the window.
*/
void setTransparentRegion(IWindow window, in Region region);
-
+
/**
* Tell the window manager about the content and visible insets of the
* given window, which can be used to adjust the <var>outContentInsets</var>
@@ -122,20 +122,20 @@
*/
void setInsets(IWindow window, int touchableInsets, in Rect contentInsets,
in Rect visibleInsets, in Region touchableRegion);
-
+
/**
* Return the current display size in which the window is being laid out,
* accounting for screen decorations around it.
*/
void getDisplayFrame(IWindow window, out Rect outDisplayFrame);
-
+
void finishDrawing(IWindow window);
-
+
void setInTouchMode(boolean showFocus);
boolean getInTouchMode();
-
+
boolean performHapticFeedback(IWindow window, int effectId, boolean always);
-
+
/**
* Allocate the drag's thumbnail surface. Also assigns a token that identifies
* the drag to the OS and passes that as the return value. A return value of
@@ -150,11 +150,11 @@
boolean performDrag(IWindow window, IBinder dragToken, float touchX, float touchY,
float thumbCenterX, float thumbCenterY, in ClipData data);
- /**
- * Report the result of a drop action targeted to the given window.
- * consumed is 'true' when the drop was accepted by a valid recipient,
- * 'false' otherwise.
- */
+ /**
+ * Report the result of a drop action targeted to the given window.
+ * consumed is 'true' when the drop was accepted by a valid recipient,
+ * 'false' otherwise.
+ */
void reportDropResult(IWindow window, boolean consumed);
/**
@@ -174,12 +174,12 @@
* how big the increment is from one screen to another.
*/
void setWallpaperPosition(IBinder windowToken, float x, float y, float xstep, float ystep);
-
+
void wallpaperOffsetsComplete(IBinder window);
-
+
Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, in Bundle extras, boolean sync);
-
+
void wallpaperCommandComplete(IBinder window, in Bundle result);
void setUniverseTransform(IBinder window, float alpha, float offx, float offy,
@@ -188,7 +188,7 @@
/**
* Notifies that a rectangle on the screen has been requested.
*/
- void onRectangleOnScreenRequested(IBinder token, in Rect rectangle, boolean immediate);
+ void onRectangleOnScreenRequested(IBinder token, in Rect rectangle);
IWindowId getWindowId(IBinder window);
}
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 4631b64..d86b699 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.graphics.Matrix;
import android.graphics.Outline;
+import android.graphics.Paint;
import java.util.ArrayList;
import java.util.List;
@@ -322,11 +323,13 @@
* handled in the drawLayer operation directly (and more efficiently).
*
* @param caching true if the display list represents a hardware layer, false otherwise.
- *
- * @hide
*/
- public boolean setCaching(boolean caching) {
- return nSetCaching(mNativeRenderNode, caching);
+ public boolean setLayerType(int layerType) {
+ return nSetLayerType(mNativeRenderNode, layerType);
+ }
+
+ public boolean setLayerPaint(Paint paint) {
+ return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.mNativePaint : 0);
}
/**
@@ -842,13 +845,6 @@
}
/**
- * Sets the scroll position, this is used for damage calculations
- */
- public void setScrollPosition(int x, int y) {
- nSetScrollPosition(mNativeRenderNode, x, y);
- }
-
- /**
* Outputs the display list to the log. This method exists for use by
* tools to output display lists for selected nodes to the log.
*
@@ -906,11 +902,11 @@
private static native boolean nSetRight(long renderNode, int right);
private static native boolean nSetTop(long renderNode, int top);
private static native boolean nSetLeft(long renderNode, int left);
- private static native void nSetScrollPosition(long renderNode, int scrollX, int scrollY);
private static native boolean nSetCameraDistance(long renderNode, float distance);
private static native boolean nSetPivotY(long renderNode, float pivotY);
private static native boolean nSetPivotX(long renderNode, float pivotX);
- private static native boolean nSetCaching(long renderNode, boolean caching);
+ private static native boolean nSetLayerType(long renderNode, int layerType);
+ private static native boolean nSetLayerPaint(long renderNode, long paint);
private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds);
private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject);
private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 5cd3d62..79f19b5 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -78,8 +78,8 @@
IBinder displayToken);
private static native int nativeGetActiveConfig(IBinder displayToken);
private static native boolean nativeSetActiveConfig(IBinder displayToken, int id);
- private static native void nativeBlankDisplay(IBinder displayToken);
- private static native void nativeUnblankDisplay(IBinder displayToken);
+ private static native void nativeSetDisplayPowerMode(
+ IBinder displayToken, int mode);
private final CloseGuard mCloseGuard = CloseGuard.get();
@@ -209,6 +209,25 @@
*/
public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
+ /* Display power modes * /
+
+ /**
+ * Display power mode off: used while blanking the screen.
+ * Use only with {@link SurfaceControl#setDisplayPowerMode()}.
+ */
+ public static final int POWER_MODE_OFF = 0;
+
+ /**
+ * Display power mode doze: used while putting the screen into low power mode.
+ * Use only with {@link SurfaceControl#setDisplayPowerMode()}.
+ */
+ public static final int POWER_MODE_DOZE = 1;
+
+ /**
+ * Display power mode normal: used while unblanking the screen.
+ * Use only with {@link SurfaceControl#setDisplayPowerMode()}.
+ */
+ public static final int POWER_MODE_NORMAL = 2;
/**
@@ -487,18 +506,11 @@
}
}
- public static void unblankDisplay(IBinder displayToken) {
+ public static void setDisplayPowerMode(IBinder displayToken, int mode) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- nativeUnblankDisplay(displayToken);
- }
-
- public static void blankDisplay(IBinder displayToken) {
- if (displayToken == null) {
- throw new IllegalArgumentException("displayToken must not be null");
- }
- nativeBlankDisplay(displayToken);
+ nativeSetDisplayPowerMode(displayToken, mode);
}
public static SurfaceControl.PhysicalDisplayInfo[] getDisplayConfigs(IBinder displayToken) {
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 2a9f7d5..1f7eaa2 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -275,6 +275,11 @@
}
}
+ @Override
+ public void setLayerPaint(Paint paint) {
+ setLayerType(/* ignored */ 0, paint);
+ }
+
/**
* Always returns {@link #LAYER_TYPE_HARDWARE}.
*/
@@ -332,11 +337,6 @@
}
}
- @Override
- boolean destroyLayer(boolean valid) {
- return false;
- }
-
/**
* @hide
*/
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 7bbe84e..166edc2 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -16,21 +16,29 @@
package android.view;
+import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
+import android.graphics.drawable.Drawable;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.Trace;
import android.util.Log;
+import android.util.LongSparseArray;
import android.util.TimeUtils;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
/**
* Hardware renderer that proxies the rendering to a render thread. Most calls
@@ -71,8 +79,8 @@
private Choreographer mChoreographer;
private boolean mProfilingEnabled;
- ThreadedRenderer(boolean translucent) {
- AtlasInitializer.sInstance.init();
+ ThreadedRenderer(Context context, boolean translucent) {
+ AtlasInitializer.sInstance.init(context);
long rootNodePtr = nCreateRootRenderNode();
mRootNode = RenderNode.adopt(rootNodePtr);
@@ -257,12 +265,6 @@
}
@Override
- HardwareLayer createDisplayListLayer(int width, int height) {
- long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
- return HardwareLayer.adoptDisplayListLayer(this, layer);
- }
-
- @Override
HardwareLayer createTextureLayer() {
long layer = nCreateTextureLayer(mNativeProxy);
return HardwareLayer.adoptTextureLayer(this, layer);
@@ -340,7 +342,7 @@
private AtlasInitializer() {}
- synchronized void init() {
+ synchronized void init(Context context) {
if (mInitialized) return;
IBinder binder = ServiceManager.getService("assetatlas");
if (binder == null) return;
@@ -352,6 +354,8 @@
if (buffer != null) {
long[] map = atlas.getMap();
if (map != null) {
+ // TODO Remove after fixing b/15425820
+ validateMap(context, map);
nSetAtlas(buffer, map);
mInitialized = true;
}
@@ -367,6 +371,30 @@
Log.w(LOG_TAG, "Could not acquire atlas", e);
}
}
+
+ private static void validateMap(Context context, long[] map) {
+ Log.d("Atlas", "Validating map...");
+ HashSet<Long> preloadedPointers = new HashSet<Long>();
+
+ // We only care about drawables that hold bitmaps
+ final Resources resources = context.getResources();
+ final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables();
+
+ final int count = drawables.size();
+ for (int i = 0; i < count; i++) {
+ final Bitmap bitmap = drawables.valueAt(i).getBitmap();
+ if (bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888) {
+ preloadedPointers.add(bitmap.mNativeBitmap);
+ }
+ }
+
+ for (int i = 0; i < map.length; i += 4) {
+ if (!preloadedPointers.contains(map[i])) {
+ Log.w("Atlas", String.format("Pointer 0x%X, not in getPreloadedDrawables?", map[i]));
+ map[i] = 0;
+ }
+ }
+ }
}
static native void setupShadersDiskCache(String cacheFile);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e97a768..9156216 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -25,6 +25,7 @@
import android.annotation.Nullable;
import android.content.ClipData;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -44,6 +45,7 @@
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Shader;
+import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManagerGlobal;
@@ -90,6 +92,7 @@
import com.android.internal.R;
import com.android.internal.util.Predicate;
import com.android.internal.view.menu.MenuBuilder;
+
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -431,7 +434,7 @@
* child. The child must use this size, and guarantee that all of its
* descendants will fit within this size.
* <li>AT_MOST: This is used by the parent to impose a maximum size on the
- * child. The child must gurantee that it and all of its descendants will fit
+ * child. The child must guarantee that it and all of its descendants will fit
* within this size.
* </ul>
* </p>
@@ -2775,6 +2778,13 @@
/**
* @hide
*
+ * Whether Recents is visible or not.
+ */
+ public static final int RECENT_APPS_VISIBLE = 0x00004000;
+
+ /**
+ * @hide
+ *
* Makes system ui transparent.
*/
public static final int SYSTEM_UI_TRANSPARENT = 0x00008000;
@@ -2782,7 +2792,7 @@
/**
* @hide
*/
- public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00007FFF;
+ public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FFF;
/**
* These are the system UI flags that can be cleared by events outside
@@ -3179,6 +3189,9 @@
@ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_")
private Drawable mBackground;
+ private ColorStateList mBackgroundTint = null;
+ private PorterDuff.Mode mBackgroundTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasBackgroundTint = false;
/**
* Display list used for backgrounds.
@@ -3465,8 +3478,6 @@
})
int mLayerType = LAYER_TYPE_NONE;
Paint mLayerPaint;
- Rect mLocalDirtyRect;
- private HardwareLayer mHardwareLayer;
/**
* Set to true when drawing cache is enabled and cannot be created.
@@ -4016,6 +4027,16 @@
setStateListAnimator(AnimatorInflater.loadStateListAnimator(context,
a.getResourceId(attr, 0)));
break;
+ case R.styleable.View_backgroundTint:
+ // This will get applied later during setBackground().
+ mBackgroundTint = a.getColorStateList(R.styleable.View_backgroundTint);
+ mHasBackgroundTint = true;
+ break;
+ case R.styleable.View_backgroundTintMode:
+ // This will get applied later during setBackground().
+ mBackgroundTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.View_backgroundTintMode, -1), mBackgroundTintMode);
+ break;
}
}
@@ -4789,14 +4810,10 @@
* @param v previous or the next focus holder, or null if none
*/
private void manageFocusHotspot(boolean focused, View v) {
- if (mBackground == null) {
- return;
- }
-
final Rect r = new Rect();
- if (!focused && v != null) {
+ if (!focused && v != null && mAttachInfo != null) {
v.getBoundsOnScreen(r);
- final int[] location = new int[2];
+ final int[] location = mAttachInfo.mTmpLocation;
getLocationOnScreen(location);
r.offset(-location[0], -location[1]);
} else {
@@ -4805,7 +4822,20 @@
final float x = r.exactCenterX();
final float y = r.exactCenterY();
- mBackground.setHotspot(x, y);
+ setDrawableHotspot(x, y);
+ }
+
+ /**
+ * Sets the hotspot position for this View's drawables.
+ *
+ * @param x hotspot x coordinate
+ * @param y hotspot y coordinate
+ * @hide
+ */
+ protected void setDrawableHotspot(float x, float y) {
+ if (mBackground != null) {
+ mBackground.setHotspot(x, y);
+ }
}
/**
@@ -5377,8 +5407,9 @@
* Gets the location of this view in screen coordintates.
*
* @param outRect The output location
+ * @hide
*/
- void getBoundsOnScreen(Rect outRect) {
+ public void getBoundsOnScreen(Rect outRect) {
if (mAttachInfo == null) {
return;
}
@@ -6100,12 +6131,18 @@
*/
protected boolean fitSystemWindows(Rect insets) {
if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) {
+ if (insets == null) {
+ // Null insets by definition have already been consumed.
+ // This call cannot apply insets since there are none to apply,
+ // so return false.
+ return false;
+ }
// If we're not in the process of dispatching the newer apply insets call,
// that means we're not in the compatibility path. Dispatch into the newer
// apply insets path and take things from there.
try {
mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS;
- return !dispatchApplyWindowInsets(new WindowInsets(insets)).hasInsets();
+ return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed();
} finally {
mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS;
}
@@ -6761,7 +6798,7 @@
*/
private void setPressed(boolean pressed, float x, float y) {
if (pressed) {
- setHotspot(x, y);
+ setDrawableHotspot(x, y);
}
setPressed(pressed);
@@ -7648,7 +7685,7 @@
* notification is at at most once every
* {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}
* to avoid unnecessary load to the system. Also once a view has a pending
- * notifucation this method is a NOP until the notification has been sent.
+ * notification this method is a NOP until the notification has been sent.
*
* @hide
*/
@@ -9100,8 +9137,7 @@
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
} else {
// Not inside a scrolling container, so show the feedback right away
- setHotspot(x, y);
- setPressed(true);
+ setPressed(true, x, y);
checkForLongClick(0);
}
break;
@@ -9113,7 +9149,7 @@
break;
case MotionEvent.ACTION_MOVE:
- setHotspot(x, y);
+ setDrawableHotspot(x, y);
// Be lenient about moving outside of buttons
if (!pointInView(x, y, mTouchSlop)) {
@@ -9135,12 +9171,6 @@
return false;
}
- private void setHotspot(float x, float y) {
- if (mBackground != null) {
- mBackground.setHotspot(x, y);
- }
- }
-
/**
* @hide
*/
@@ -9670,7 +9700,7 @@
/**
* The transform matrix of this view, which is calculated based on the current
- * roation, scale, and pivot properties.
+ * rotation, scale, and pivot properties.
*
* @see #getRotation()
* @see #getScaleX()
@@ -10521,13 +10551,18 @@
setTranslationZ(z - getElevation());
}
+ /**
+ * The base elevation of this view relative to its parent, in pixels.
+ *
+ * @return The base depth position of the view, in pixels.
+ */
@ViewDebug.ExportedProperty(category = "drawing")
public float getElevation() {
return mRenderNode.getElevation();
}
/**
- * Sets the base depth location of this view.
+ * Sets the base elevation of this view, in pixels.
*
* @attr ref android.R.styleable#View_elevation
*/
@@ -12925,7 +12960,6 @@
stopNestedScroll();
destroyDrawingCache();
- destroyLayer(false);
cleanupDraw();
mCurrentAnimation = null;
@@ -13403,28 +13437,25 @@
+ "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE");
}
- if (layerType == mLayerType) {
+ boolean typeChanged = mRenderNode.setLayerType(layerType);
+
+ if (!typeChanged) {
setLayerPaint(paint);
return;
}
// Destroy any previous software drawing cache if needed
- switch (mLayerType) {
- case LAYER_TYPE_HARDWARE:
- destroyLayer(false);
- // fall through - non-accelerated views may use software layer mechanism instead
- case LAYER_TYPE_SOFTWARE:
- destroyDrawingCache();
- break;
- default:
- break;
+ if (mLayerType == LAYER_TYPE_SOFTWARE) {
+ destroyDrawingCache();
}
mLayerType = layerType;
- final boolean layerDisabled = mLayerType == LAYER_TYPE_NONE;
+ final boolean layerDisabled = (mLayerType == LAYER_TYPE_NONE);
mLayerPaint = layerDisabled ? null : (paint == null ? new Paint() : paint);
- mLocalDirtyRect = layerDisabled ? null : new Rect();
+ mRenderNode.setLayerPaint(mLayerPaint);
+ // draw() behaves differently if we are on a layer, so we need to
+ // invalidate() here
invalidateParentCaches();
invalidate(true);
}
@@ -13459,11 +13490,9 @@
if (layerType != LAYER_TYPE_NONE) {
mLayerPaint = paint == null ? new Paint() : paint;
if (layerType == LAYER_TYPE_HARDWARE) {
- HardwareLayer layer = getHardwareLayer();
- if (layer != null) {
- layer.setLayerPaint(mLayerPaint);
+ if (mRenderNode.setLayerPaint(mLayerPaint)) {
+ invalidateViewProperty(false, false);
}
- invalidateViewProperty(false, false);
} else {
invalidate();
}
@@ -13519,18 +13548,17 @@
throw new IllegalStateException("This view must be attached to a window first");
}
+ if (getWidth() == 0 || getHeight() == 0) {
+ return;
+ }
+
switch (mLayerType) {
case LAYER_TYPE_HARDWARE:
- getHardwareLayer();
- // TODO: We need a better way to handle this case
- // If views have registered pre-draw listeners they need
- // to be notified before we build the layer. Those listeners
- // may however rely on other events to happen first so we
- // cannot just invoke them here until they don't cancel the
- // current frame
- if (!attachInfo.mTreeObserver.hasOnPreDrawListeners()) {
- attachInfo.mViewRootImpl.dispatchFlushHardwareLayerUpdates();
- }
+ // The only part of a hardware layer we can build in response to
+ // this call is to ensure the display list is up to date.
+ // The actual rendering of the display list into the layer must
+ // be done at playback time
+ updateDisplayListIfDirty();
break;
case LAYER_TYPE_SOFTWARE:
buildDrawingCache(true);
@@ -13539,70 +13567,13 @@
}
/**
- * <p>Returns a hardware layer that can be used to draw this view again
- * without executing its draw method.</p>
+ * If this View draws with a HardwareLayer, returns it.
+ * Otherwise returns null
*
- * @return A HardwareLayer ready to render, or null if an error occurred.
+ * TODO: Only TextureView uses this, can we eliminate it?
*/
HardwareLayer getHardwareLayer() {
- if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null ||
- !mAttachInfo.mHardwareRenderer.isEnabled()) {
- return null;
- }
-
- final int width = mRight - mLeft;
- final int height = mBottom - mTop;
-
- if (width == 0 || height == 0) {
- return null;
- }
-
- if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || mHardwareLayer == null) {
- if (mHardwareLayer == null) {
- mHardwareLayer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
- width, height);
- mLocalDirtyRect.set(0, 0, width, height);
- } else if (mHardwareLayer.isValid()) {
- // This should not be necessary but applications that change
- // the parameters of their background drawable without calling
- // this.setBackground(Drawable) can leave the view in a bad state
- // (for instance isOpaque() returns true, but the background is
- // not opaque.)
- computeOpaqueFlags();
-
- if (mHardwareLayer.prepare(width, height, isOpaque())) {
- mLocalDirtyRect.set(0, 0, width, height);
- }
- }
-
- mHardwareLayer.setLayerPaint(mLayerPaint);
- RenderNode displayList = mHardwareLayer.startRecording();
- updateDisplayListIfDirty(displayList, true);
- mHardwareLayer.endRecording(mLocalDirtyRect);
- mLocalDirtyRect.setEmpty();
- }
-
- return mHardwareLayer;
- }
-
- /**
- * Destroys this View's hardware layer if possible.
- *
- * @return True if the layer was destroyed, false otherwise.
- *
- * @see #setLayerType(int, android.graphics.Paint)
- * @see #LAYER_TYPE_HARDWARE
- */
- boolean destroyLayer(boolean valid) {
- if (mHardwareLayer != null) {
- mHardwareLayer.destroy();
- mHardwareLayer = null;
-
- invalidate(true);
- invalidateParentCaches();
- return true;
- }
- return false;
+ return null;
}
/**
@@ -13618,7 +13589,6 @@
*/
protected void destroyHardwareResources() {
resetDisplayList();
- destroyLayer(true);
}
/**
@@ -13713,33 +13683,19 @@
return !(mAttachInfo == null || mAttachInfo.mHardwareRenderer == null);
}
- /**
- * Returns a DisplayList. If the incoming displayList is null, one will be created.
- * Otherwise, the same display list will be returned (after having been rendered into
- * along the way, depending on the invalidation state of the view).
- *
- * @param renderNode The previous version of this displayList, could be null.
- * @param isLayer Whether the requester of the display list is a layer. If so,
- * the view will avoid creating a layer inside the resulting display list.
- * @return A new or reused DisplayList object.
- */
- private void updateDisplayListIfDirty(@NonNull RenderNode renderNode, boolean isLayer) {
- if (renderNode == null) {
- throw new IllegalArgumentException("RenderNode must not be null");
- }
+ private void updateDisplayListIfDirty() {
+ final RenderNode renderNode = mRenderNode;
if (!canHaveDisplayList()) {
// can't populate RenderNode, don't try
return;
}
- renderNode.setScrollPosition(mScrollX, mScrollY);
if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
|| !renderNode.isValid()
- || (!isLayer && mRecreateDisplayList)) {
+ || (mRecreateDisplayList)) {
// Don't need to recreate the display list, just need to tell our
// children to restore/recreate theirs
if (renderNode.isValid()
- && !isLayer
&& !mRecreateDisplayList) {
mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
@@ -13748,13 +13704,10 @@
return; // no work needed
}
- if (!isLayer) {
- // If we got here, we're recreating it. Mark it as such to ensure that
- // we copy in child display lists into ours in drawChild()
- mRecreateDisplayList = true;
- }
+ // If we got here, we're recreating it. Mark it as such to ensure that
+ // we copy in child display lists into ours in drawChild()
+ mRecreateDisplayList = true;
- boolean caching = false;
int width = mRight - mLeft;
int height = mBottom - mTop;
int layerType = getLayerType();
@@ -13762,34 +13715,21 @@
final HardwareCanvas canvas = renderNode.start(width, height);
try {
- if (!isLayer && layerType != LAYER_TYPE_NONE) {
- if (layerType == LAYER_TYPE_HARDWARE) {
- final HardwareLayer layer = getHardwareLayer();
- if (layer != null && layer.isValid()) {
- canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint);
- } else {
- canvas.saveLayer(0, 0, mRight - mLeft, mBottom - mTop, mLayerPaint,
- Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
- Canvas.CLIP_TO_LAYER_SAVE_FLAG);
- }
- caching = true;
- } else {
- buildDrawingCache(true);
- Bitmap cache = getDrawingCache(true);
- if (cache != null) {
- canvas.drawBitmap(cache, 0, 0, mLayerPaint);
- caching = true;
- }
+ final HardwareLayer layer = getHardwareLayer();
+ if (layer != null && layer.isValid()) {
+ canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint);
+ } else if (layerType == LAYER_TYPE_SOFTWARE) {
+ buildDrawingCache(true);
+ Bitmap cache = getDrawingCache(true);
+ if (cache != null) {
+ canvas.drawBitmap(cache, 0, 0, mLayerPaint);
}
} else {
-
computeScroll();
canvas.translate(-mScrollX, -mScrollY);
- if (!isLayer) {
- mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
- mPrivateFlags &= ~PFLAG_DIRTY_MASK;
- }
+ mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
+ mPrivateFlags &= ~PFLAG_DIRTY_MASK;
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
@@ -13803,14 +13743,9 @@
}
} finally {
renderNode.end(canvas);
- renderNode.setCaching(caching);
- if (isLayer) {
- renderNode.setLeftTopRightBottom(0, 0, width, height);
- } else {
- setDisplayListProperties(renderNode);
- }
+ setDisplayListProperties(renderNode);
}
- } else if (!isLayer) {
+ } else {
mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
}
@@ -13825,7 +13760,7 @@
* @hide
*/
public RenderNode getDisplayList() {
- updateDisplayListIfDirty(mRenderNode, false);
+ updateDisplayListIfDirty();
return mRenderNode;
}
@@ -15778,7 +15713,7 @@
return;
}
- Drawable d= null;
+ Drawable d = null;
if (resid != 0) {
d = mContext.getDrawable(resid);
}
@@ -15854,8 +15789,9 @@
// Compare the minimum sizes of the old Drawable and the new. If there isn't an old or
// if it has a different minimum size, we should layout again
- if (mBackground == null || mBackground.getMinimumHeight() != background.getMinimumHeight() ||
- mBackground.getMinimumWidth() != background.getMinimumWidth()) {
+ if (mBackground == null
+ || mBackground.getMinimumHeight() != background.getMinimumHeight()
+ || mBackground.getMinimumWidth() != background.getMinimumWidth()) {
requestLayout = true;
}
@@ -15866,6 +15802,8 @@
background.setVisible(getVisibility() == VISIBLE, false);
mBackground = background;
+ applyBackgroundTint();
+
if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) {
mPrivateFlags &= ~PFLAG_SKIP_DRAW;
mPrivateFlags |= PFLAG_ONLY_DRAWS_BACKGROUND;
@@ -15921,6 +15859,88 @@
}
/**
+ * Applies a tint to the background drawable.
+ * <p>
+ * Subsequent calls to {@link #setBackground(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#View_backgroundTint
+ * @attr ref android.R.styleable#View_backgroundTintMode
+ * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+ */
+ private void setBackgroundTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mBackgroundTint = tint;
+ mBackgroundTintMode = tintMode;
+ mHasBackgroundTint = true;
+
+ applyBackgroundTint();
+ }
+
+ /**
+ * Applies a tint to the background drawable. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setBackground(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#View_backgroundTint
+ * @see #setBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setBackgroundTint(@Nullable ColorStateList tint) {
+ setBackgroundTint(tint, mBackgroundTintMode);
+ }
+
+ /**
+ * @return the tint applied to the background drawable
+ * @attr ref android.R.styleable#View_backgroundTint
+ * @see #setBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getBackgroundTint() {
+ return mBackgroundTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setBackgroundTint(ColorStateList)}} to the background drawable.
+ * The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#View_backgroundTintMode
+ * @see #setBackgroundTint(ColorStateList)
+ */
+ public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setBackgroundTint(mBackgroundTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the background drawable
+ * @attr ref android.R.styleable#View_backgroundTintMode
+ * @see #setBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getBackgroundTintMode() {
+ return mBackgroundTintMode;
+ }
+
+ private void applyBackgroundTint() {
+ if (mBackground != null && mHasBackgroundTint) {
+ mBackground = mBackground.mutate();
+ mBackground.setTint(mBackgroundTint, mBackgroundTintMode);
+ }
+ }
+
+ /**
* 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},
@@ -19845,6 +19865,11 @@
*/
final int[] mInvalidateChildLocation = new int[2];
+ /**
+ * Global to the view hierarchy used as a temporary for dealng with
+ * computing absolute on-screen location.
+ */
+ final int[] mTmpLocation = new int[2];
/**
* Global to the view hierarchy used as a temporary for dealing with
diff --git a/core/java/android/view/ViewAnimationUtils.java b/core/java/android/view/ViewAnimationUtils.java
index 3854f34..29e865f 100644
--- a/core/java/android/view/ViewAnimationUtils.java
+++ b/core/java/android/view/ViewAnimationUtils.java
@@ -23,7 +23,7 @@
* Defines common utilities for working with View's animations.
*
*/
-public class ViewAnimationUtils {
+public final class ViewAnimationUtils {
private ViewAnimationUtils() {}
/**
* Returns a ValueAnimator which can animate a clipping circle.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 02011e0..a02e76b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4386,10 +4386,9 @@
// Make sure we do not set both flags at the same time
int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
- if (child.mLayerType != LAYER_TYPE_NONE) {
+ if (child.mLayerType == LAYER_TYPE_SOFTWARE) {
mPrivateFlags |= PFLAG_INVALIDATED;
mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
- child.mLocalDirtyRect.union(dirty);
}
final int[] location = attachInfo.mInvalidateChildLocation;
@@ -4498,9 +4497,8 @@
location[CHILD_LEFT_INDEX] = left;
location[CHILD_TOP_INDEX] = top;
- if (mLayerType != LAYER_TYPE_NONE) {
+ if (mLayerType == LAYER_TYPE_SOFTWARE) {
mPrivateFlags |= PFLAG_INVALIDATED;
- mLocalDirtyRect.union(dirty);
}
return mParent;
@@ -4517,9 +4515,8 @@
dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
}
- if (mLayerType != LAYER_TYPE_NONE) {
+ if (mLayerType == LAYER_TYPE_SOFTWARE) {
mPrivateFlags |= PFLAG_INVALIDATED;
- mLocalDirtyRect.union(dirty);
}
return mParent;
@@ -4567,10 +4564,6 @@
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
- if (child.mLayerType != LAYER_TYPE_NONE) {
- child.mLocalDirtyRect.union(dirty);
- }
-
int left = child.mLeft;
int top = child.mTop;
if (!child.getMatrix().isIdentity()) {
@@ -4618,9 +4611,6 @@
if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0 ||
dirty.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
- if (mLayerType != LAYER_TYPE_NONE) {
- mLocalDirtyRect.union(dirty);
- }
if (!getMatrix().isIdentity()) {
transformRect(dirty);
}
@@ -5600,11 +5590,11 @@
@Override
public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
insets = super.dispatchApplyWindowInsets(insets);
- if (insets.hasInsets()) {
+ if (!insets.isConsumed()) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
insets = getChildAt(i).dispatchApplyWindowInsets(insets);
- if (!insets.hasInsets()) {
+ if (insets.isConsumed()) {
break;
}
}
@@ -6939,13 +6929,9 @@
if (getClass() != another.getClass()) {
return 1;
}
- // First is above second.
- if (mLocation.bottom - another.mLocation.top <= 0) {
- return -1;
- }
- // First is below second.
- if (mLocation.top - another.mLocation.bottom >= 0) {
- return 1;
+ final int topDiference = mLocation.top - another.mLocation.top;
+ if (topDiference != 0) {
+ return topDiference;
}
// LTR
if (mLayoutDirection == LAYOUT_DIRECTION_LTR) {
@@ -6961,11 +6947,6 @@
return -rightDifference;
}
}
- // Break tie by top.
- final int topDiference = mLocation.top - another.mLocation.top;
- if (topDiference != 0) {
- return topDiference;
- }
// Break tie by height.
final int heightDiference = mLocation.height() - another.mLocation.height();
if (heightDiference != 0) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 76d5038..82e5ddd 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -631,27 +631,7 @@
}
void destroyHardwareLayers() {
- if (mThread != Thread.currentThread()) {
- if (mAttachInfo.mHardwareRenderer != null &&
- mAttachInfo.mHardwareRenderer.isEnabled()) {
- HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
- }
- } else {
- destroyHardwareLayer(mView);
- }
- }
-
- private static void destroyHardwareLayer(View view) {
- view.destroyLayer(true);
-
- if (view instanceof ViewGroup) {
- ViewGroup group = (ViewGroup) view;
-
- int count = group.getChildCount();
- for (int i = 0; i < count; i++) {
- destroyHardwareLayer(group.getChildAt(i));
- }
- }
+ // TODO Implement
}
void flushHardwareLayerUpdates() {
@@ -676,7 +656,7 @@
}
public boolean invokeFunctor(long functor, boolean waitForCompletion) {
- if (mAttachInfo.mHardwareRenderer == null || !mAttachInfo.mHardwareRenderer.isEnabled()) {
+ if (mAttachInfo.mHardwareRenderer == null) {
return false;
}
mAttachInfo.mHardwareRenderer.invokeFunctor(functor, waitForCompletion);
@@ -720,7 +700,7 @@
}
final boolean translucent = attrs.format != PixelFormat.OPAQUE;
- mAttachInfo.mHardwareRenderer = HardwareRenderer.create(translucent);
+ mAttachInfo.mHardwareRenderer = HardwareRenderer.create(mContext, translucent);
if (mAttachInfo.mHardwareRenderer != null) {
mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
mAttachInfo.mHardwareAccelerated =
@@ -1520,54 +1500,55 @@
disposeResizeBuffer();
- if (mResizeBuffer == null) {
- mResizeBuffer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
- mWidth, mHeight);
- }
- mResizeBuffer.prepare(mWidth, mHeight, false);
- RenderNode layerRenderNode = mResizeBuffer.startRecording();
- HardwareCanvas layerCanvas = layerRenderNode.start(mWidth, mHeight);
- try {
- final int restoreCount = layerCanvas.save();
-
- int yoff;
- final boolean scrolling = mScroller != null
- && mScroller.computeScrollOffset();
- if (scrolling) {
- yoff = mScroller.getCurrY();
- mScroller.abortAnimation();
- } else {
- yoff = mScrollY;
- }
-
- layerCanvas.translate(0, -yoff);
- if (mTranslator != null) {
- mTranslator.translateCanvas(layerCanvas);
- }
-
- RenderNode renderNode = mView.mRenderNode;
- if (renderNode != null && renderNode.isValid()) {
- layerCanvas.drawDisplayList(renderNode, null,
- RenderNode.FLAG_CLIP_CHILDREN);
- } else {
- mView.draw(layerCanvas);
- }
-
- drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
-
- mResizeBufferStartTime = SystemClock.uptimeMillis();
- mResizeBufferDuration = mView.getResources().getInteger(
- com.android.internal.R.integer.config_mediumAnimTime);
-
- layerCanvas.restoreToCount(restoreCount);
- layerRenderNode.end(layerCanvas);
- layerRenderNode.setCaching(true);
- layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
- mTempRect.set(0, 0, mWidth, mHeight);
- } finally {
- mResizeBuffer.endRecording(mTempRect);
- }
- mAttachInfo.mHardwareRenderer.flushLayerUpdates();
+// TODO: Again....
+// if (mResizeBuffer == null) {
+// mResizeBuffer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
+// mWidth, mHeight);
+// }
+// mResizeBuffer.prepare(mWidth, mHeight, false);
+// RenderNode layerRenderNode = mResizeBuffer.startRecording();
+// HardwareCanvas layerCanvas = layerRenderNode.start(mWidth, mHeight);
+// try {
+// final int restoreCount = layerCanvas.save();
+//
+// int yoff;
+// final boolean scrolling = mScroller != null
+// && mScroller.computeScrollOffset();
+// if (scrolling) {
+// yoff = mScroller.getCurrY();
+// mScroller.abortAnimation();
+// } else {
+// yoff = mScrollY;
+// }
+//
+// layerCanvas.translate(0, -yoff);
+// if (mTranslator != null) {
+// mTranslator.translateCanvas(layerCanvas);
+// }
+//
+// RenderNode renderNode = mView.mRenderNode;
+// if (renderNode != null && renderNode.isValid()) {
+// layerCanvas.drawDisplayList(renderNode, null,
+// RenderNode.FLAG_CLIP_CHILDREN);
+// } else {
+// mView.draw(layerCanvas);
+// }
+//
+// drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
+//
+// mResizeBufferStartTime = SystemClock.uptimeMillis();
+// mResizeBufferDuration = mView.getResources().getInteger(
+// com.android.internal.R.integer.config_mediumAnimTime);
+//
+// layerCanvas.restoreToCount(restoreCount);
+// layerRenderNode.end(layerCanvas);
+// layerRenderNode.setCaching(true);
+// layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
+// mTempRect.set(0, 0, mWidth, mHeight);
+// } finally {
+// mResizeBuffer.endRecording(mTempRect);
+// }
+// mAttachInfo.mHardwareRenderer.flushLayerUpdates();
}
mAttachInfo.mContentInsets.set(mPendingContentInsets);
if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
@@ -6215,7 +6196,7 @@
mTempRect.offset(0, -mCurScrollY);
mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
try {
- mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect, immediate);
+ mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
} catch (RemoteException re) {
/* ignore */
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index ecc4586..0120875 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1516,6 +1516,29 @@
public boolean getAllowExitTransitionOverlap() { return true; }
/**
+ * Returns the duration, in milliseconds, of the window background fade
+ * when transitioning into or away from an Activity when called with an Activity Transition.
+ * <p>When executing the enter transition, the background starts transparent
+ * and fades in. This requires {@link #FEATURE_CONTENT_TRANSITIONS}. The default is
+ * 300 milliseconds.</p>
+ * @return The duration of the window background fade to opaque during enter transition.
+ * @see #getEnterTransition()
+ */
+ public long getTransitionBackgroundFadeDuration() { return 0; }
+
+ /**
+ * Sets the duration, in milliseconds, of the window background fade
+ * when transitioning into or away from an Activity when called with an Activity Transition.
+ * <p>When executing the enter transition, the background starts transparent
+ * and fades in. This requires {@link #FEATURE_CONTENT_TRANSITIONS}. The default is
+ * 300 milliseconds.</p>
+ * @param fadeDurationMillis The duration of the window background fade to or from opaque
+ * during enter transition.
+ * @see #setEnterTransition(android.transition.Transition)
+ */
+ public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) { }
+
+ /**
* @return the color of the status bar.
*/
public abstract int getStatusBarColor();
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index 7f89044..b721074 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -111,6 +111,7 @@
builder.append("type=").append(type);
builder.append(", layer=").append(layer);
builder.append(", token=").append(token);
+ builder.append(", bounds=").append(boundsInScreen);
builder.append(", parent=").append(parentToken);
builder.append(", focused=").append(focused);
builder.append(", children=").append(childTokens);
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 294f472..1d2f1bf 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -35,6 +35,9 @@
private Rect mTempRect;
private boolean mIsRound;
+ private boolean mSystemWindowInsetsConsumed = false;
+ private boolean mWindowDecorInsetsConsumed = false;
+
private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
/**
@@ -43,7 +46,13 @@
* since it would allow them to inadvertently consume unknown insets by returning it.
* @hide
*/
- public static final WindowInsets EMPTY = new WindowInsets(EMPTY_RECT, EMPTY_RECT);
+ public static final WindowInsets CONSUMED;
+
+ static {
+ CONSUMED = new WindowInsets(EMPTY_RECT, EMPTY_RECT);
+ CONSUMED.mSystemWindowInsetsConsumed = true;
+ CONSUMED.mWindowDecorInsetsConsumed = true;
+ }
/** @hide */
public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets) {
@@ -52,13 +61,17 @@
/** @hide */
public WindowInsets(Rect systemWindowInsets, boolean isRound) {
- this(systemWindowInsets, EMPTY_RECT, isRound);
+ this(systemWindowInsets, null, isRound);
}
/** @hide */
public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, boolean isRound) {
- mSystemWindowInsets = systemWindowInsets;
- mWindowDecorInsets = windowDecorInsets;
+ mSystemWindowInsetsConsumed = systemWindowInsets == null;
+ mSystemWindowInsets = mSystemWindowInsetsConsumed ? EMPTY_RECT : systemWindowInsets;
+
+ mWindowDecorInsetsConsumed = windowDecorInsets == null;
+ mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : windowDecorInsets;
+
mIsRound = isRound;
}
@@ -70,12 +83,14 @@
public WindowInsets(WindowInsets src) {
mSystemWindowInsets = src.mSystemWindowInsets;
mWindowDecorInsets = src.mWindowDecorInsets;
+ mSystemWindowInsetsConsumed = src.mSystemWindowInsetsConsumed;
+ mWindowDecorInsetsConsumed = src.mWindowDecorInsetsConsumed;
mIsRound = src.mIsRound;
}
/** @hide */
public WindowInsets(Rect systemWindowInsets) {
- this(systemWindowInsets, EMPTY_RECT);
+ this(systemWindowInsets, null);
}
/**
@@ -87,7 +102,12 @@
if (mTempRect == null) {
mTempRect = new Rect();
}
- mTempRect.set(mSystemWindowInsets);
+ if (mSystemWindowInsets != null) {
+ mTempRect.set(mSystemWindowInsets);
+ } else {
+ // If there were no system window insets, this is just empty.
+ mTempRect.setEmpty();
+ }
return mTempRect;
}
@@ -238,6 +258,24 @@
}
/**
+ * Check if these insets have been fully consumed.
+ *
+ * <p>Insets are considered "consumed" if the applicable <code>consume*</code> methods
+ * have been called such that all insets have been set to zero. This affects propagation of
+ * insets through the view hierarchy; insets that have not been fully consumed will continue
+ * to propagate down to child views.</p>
+ *
+ * <p>The result of this method is equivalent to the return value of
+ * {@link View#fitSystemWindows(android.graphics.Rect)}.</p>
+ *
+ * @return true if the insets have been fully consumed.
+ * @hide Pending API
+ */
+ public boolean isConsumed() {
+ return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed;
+ }
+
+ /**
* Returns true if the associated window has a round shape.
*
* <p>A round window's left, top, right and bottom edges reach all the way to the
@@ -258,7 +296,8 @@
*/
public WindowInsets consumeSystemWindowInsets() {
final WindowInsets result = new WindowInsets(this);
- result.mSystemWindowInsets = new Rect(0, 0, 0, 0);
+ result.mSystemWindowInsets = EMPTY_RECT;
+ result.mSystemWindowInsetsConsumed = true;
return result;
}
@@ -276,10 +315,12 @@
boolean right, boolean bottom) {
if (left || top || right || bottom) {
final WindowInsets result = new WindowInsets(this);
- result.mSystemWindowInsets = new Rect(left ? 0 : mSystemWindowInsets.left,
+ result.mSystemWindowInsets = new Rect(
+ left ? 0 : mSystemWindowInsets.left,
top ? 0 : mSystemWindowInsets.top,
right ? 0 : mSystemWindowInsets.right,
bottom ? 0 : mSystemWindowInsets.bottom);
+ result.mSystemWindowInsetsConsumed = !hasSystemWindowInsets();
return result;
}
return this;
@@ -299,6 +340,7 @@
int right, int bottom) {
final WindowInsets result = new WindowInsets(this);
result.mSystemWindowInsets = new Rect(left, top, right, bottom);
+ result.mSystemWindowInsetsConsumed = !hasSystemWindowInsets();
return result;
}
@@ -308,6 +350,7 @@
public WindowInsets consumeWindowDecorInsets() {
final WindowInsets result = new WindowInsets(this);
result.mWindowDecorInsets.set(0, 0, 0, 0);
+ result.mWindowDecorInsetsConsumed = true;
return result;
}
@@ -322,6 +365,7 @@
top ? 0 : mWindowDecorInsets.top,
right ? 0 : mWindowDecorInsets.right,
bottom ? 0 : mWindowDecorInsets.bottom);
+ result.mWindowDecorInsetsConsumed = !hasWindowDecorInsets();
return result;
}
return this;
@@ -333,6 +377,7 @@
public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) {
final WindowInsets result = new WindowInsets(this);
result.mWindowDecorInsets = new Rect(left, top, right, bottom);
+ result.mWindowDecorInsetsConsumed = !hasWindowDecorInsets();
return result;
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 2b4677c..d426edc 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -605,21 +605,21 @@
public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation);
/**
- * Return whether the given window should forcibly hide everything
- * behind it. Typically returns true for the keyguard.
+ * Return whether the given window is forcibly hiding all windows except windows with
+ * FLAG_SHOW_WHEN_LOCKED set. Typically returns true for the keyguard.
*/
- public boolean doesForceHide(WindowManager.LayoutParams attrs);
+ public boolean isForceHiding(WindowManager.LayoutParams attrs);
/**
- * Return whether the given window can become one that passes doesForceHide() test.
+ * Return whether the given window can become one that passes isForceHiding() test.
* Typically returns true for the StatusBar.
*/
public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs);
/**
* Determine if a window that is behind one that is force hiding
- * (as determined by {@link #doesForceHide}) should actually be hidden.
+ * (as determined by {@link #isForceHiding}) should actually be hidden.
* For example, typically returns false for the status bar. Be careful
* to return false for any window that you may hide yourself, since this
* will conflict with what you set.
@@ -830,13 +830,11 @@
* setting the window's frame, either here or in finishLayout().
*
* @param win The window being positioned.
- * @param attrs The LayoutParams of the window.
* @param attached For sub-windows, the window it is attached to; this
* window will already have had layoutWindow() called on it
* so you can use its Rect. Otherwise null.
*/
- public void layoutWindowLw(WindowState win,
- WindowManager.LayoutParams attrs, WindowState attached);
+ public void layoutWindowLw(WindowState win, WindowState attached);
/**
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 5b9372d..4748402 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -225,17 +225,11 @@
try {
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
- List<AccessibilityWindowInfo> windows = sAccessibilityCache.getWindows();
- if (windows != null) {
- if (DEBUG) {
- Log.i(LOG_TAG, "Window cache hit");
- }
- return windows;
- }
- if (DEBUG) {
- Log.i(LOG_TAG, "Window cache miss");
- }
- windows = connection.getWindows();
+ // The system is just sending data for windows that we introspected
+ // and changed but not ones that appeared, so we have to always call
+ // into the system process. This is less expensice as opposed to
+ // sending all windows on every window change.
+ List<AccessibilityWindowInfo> windows = connection.getWindows();
if (windows != null) {
final int windowCount = windows.size();
for (int i = 0; i < windowCount; i++) {
diff --git a/core/java/android/view/animation/AccelerateInterpolator.java b/core/java/android/view/animation/AccelerateInterpolator.java
index c08f348..1c75f16 100644
--- a/core/java/android/view/animation/AccelerateInterpolator.java
+++ b/core/java/android/view/animation/AccelerateInterpolator.java
@@ -17,15 +17,18 @@
package android.view.animation;
import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
- * An interpolator where the rate of change starts out slowly and
+ * An interpolator where the rate of change starts out slowly and
* and then accelerates.
*
*/
@@ -38,10 +41,10 @@
mFactor = 1.0f;
mDoubleFactor = 2.0;
}
-
+
/**
* Constructor
- *
+ *
* @param factor Degree to which the animation should be eased. Seting
* factor to 1.0f produces a y=x^2 parabola. Increasing factor above
* 1.0f exaggerates the ease-in effect (i.e., it starts even
@@ -51,17 +54,26 @@
mFactor = factor;
mDoubleFactor = 2 * mFactor;
}
-
+
public AccelerateInterpolator(Context context, AttributeSet attrs) {
- TypedArray a =
- context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AccelerateInterpolator);
-
- mFactor = a.getFloat(com.android.internal.R.styleable.AccelerateInterpolator_factor, 1.0f);
+ this(context.getResources(), context.getTheme(), attrs);
+ }
+
+ /** @hide */
+ public AccelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.AccelerateInterpolator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, R.styleable.AccelerateInterpolator);
+ }
+
+ mFactor = a.getFloat(R.styleable.AccelerateInterpolator_factor, 1.0f);
mDoubleFactor = 2 * mFactor;
a.recycle();
}
-
+
public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return input * input;
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index 1d1fa1e..af4e04f 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -20,6 +20,8 @@
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.XmlResourceParser;
import android.content.res.Resources.NotFoundException;
import android.util.AttributeSet;
@@ -143,7 +145,7 @@
*/
public static LayoutAnimationController loadLayoutAnimation(Context context, int id)
throws NotFoundException {
-
+
XmlResourceParser parser = null;
try {
parser = context.getResources().getAnimation(id);
@@ -201,7 +203,7 @@
/**
* Make an animation for objects becoming visible. Uses a slide and fade
* effect.
- *
+ *
* @param c Context for loading resources
* @param fromLeft is the object to be animated coming from the left
* @return The new animation
@@ -218,11 +220,11 @@
a.setStartTime(currentAnimationTimeMillis());
return a;
}
-
+
/**
* Make an animation for objects becoming invisible. Uses a slide and fade
* effect.
- *
+ *
* @param c Context for loading resources
* @param toRight is the object to be animated exiting to the right
* @return The new animation
@@ -234,17 +236,17 @@
} else {
a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_left);
}
-
+
a.setInterpolator(new AccelerateInterpolator());
a.setStartTime(currentAnimationTimeMillis());
return a;
}
-
+
/**
* Make an animation for objects becoming visible. Uses a slide up and fade
* effect.
- *
+ *
* @param c Context for loading resources
* @return The new animation
*/
@@ -255,10 +257,10 @@
a.setStartTime(currentAnimationTimeMillis());
return a;
}
-
+
/**
* Loads an {@link Interpolator} object from a resource
- *
+ *
* @param context Application context used to access resources
* @param id The resource id of the animation to load
* @return The animation object reference by the specified id
@@ -268,7 +270,7 @@
XmlResourceParser parser = null;
try {
parser = context.getResources().getAnimation(id);
- return createInterpolatorFromXml(context, parser);
+ return createInterpolatorFromXml(context.getResources(), context.getTheme(), parser);
} catch (XmlPullParserException ex) {
NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
Integer.toHexString(id));
@@ -284,54 +286,84 @@
}
}
-
- private static Interpolator createInterpolatorFromXml(Context c, XmlPullParser parser)
+
+ /**
+ * Loads an {@link Interpolator} object from a resource
+ *
+ * @param res The resources
+ * @param id The resource id of the animation to load
+ * @return The interpolator object reference by the specified id
+ * @throws NotFoundException
+ * @hide
+ */
+ public static Interpolator loadInterpolator(Resources res, Theme theme, int id) throws NotFoundException {
+ XmlResourceParser parser = null;
+ try {
+ parser = res.getAnimation(id);
+ return createInterpolatorFromXml(res, theme, parser);
+ } catch (XmlPullParserException ex) {
+ NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
+ Integer.toHexString(id));
+ rnf.initCause(ex);
+ throw rnf;
+ } catch (IOException ex) {
+ NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
+ Integer.toHexString(id));
+ rnf.initCause(ex);
+ throw rnf;
+ } finally {
+ if (parser != null)
+ parser.close();
+ }
+
+ }
+
+ private static Interpolator createInterpolatorFromXml(Resources res, Theme theme, XmlPullParser parser)
throws XmlPullParserException, IOException {
-
+
Interpolator interpolator = null;
-
+
// Make sure we are on a start tag.
int type;
int depth = parser.getDepth();
- while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
- && type != XmlPullParser.END_DOCUMENT) {
+ while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+ && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
AttributeSet attrs = Xml.asAttributeSet(parser);
-
- String name = parser.getName();
-
-
+
+ String name = parser.getName();
+
if (name.equals("linearInterpolator")) {
- interpolator = new LinearInterpolator(c, attrs);
+ interpolator = new LinearInterpolator();
} else if (name.equals("accelerateInterpolator")) {
- interpolator = new AccelerateInterpolator(c, attrs);
+ interpolator = new AccelerateInterpolator(res, theme, attrs);
} else if (name.equals("decelerateInterpolator")) {
- interpolator = new DecelerateInterpolator(c, attrs);
- } else if (name.equals("accelerateDecelerateInterpolator")) {
- interpolator = new AccelerateDecelerateInterpolator(c, attrs);
- } else if (name.equals("cycleInterpolator")) {
- interpolator = new CycleInterpolator(c, attrs);
+ interpolator = new DecelerateInterpolator(res, theme, attrs);
+ } else if (name.equals("accelerateDecelerateInterpolator")) {
+ interpolator = new AccelerateDecelerateInterpolator();
+ } else if (name.equals("cycleInterpolator")) {
+ interpolator = new CycleInterpolator(res, theme, attrs);
} else if (name.equals("anticipateInterpolator")) {
- interpolator = new AnticipateInterpolator(c, attrs);
+ interpolator = new AnticipateInterpolator(res, theme, attrs);
} else if (name.equals("overshootInterpolator")) {
- interpolator = new OvershootInterpolator(c, attrs);
+ interpolator = new OvershootInterpolator(res, theme, attrs);
} else if (name.equals("anticipateOvershootInterpolator")) {
- interpolator = new AnticipateOvershootInterpolator(c, attrs);
+ interpolator = new AnticipateOvershootInterpolator(res, theme, attrs);
} else if (name.equals("bounceInterpolator")) {
- interpolator = new BounceInterpolator(c, attrs);
+ interpolator = new BounceInterpolator();
} else if (name.equals("pathInterpolator")) {
- interpolator = new PathInterpolator(c, attrs);
+ interpolator = new PathInterpolator(res, theme, attrs);
} else {
throw new RuntimeException("Unknown interpolator name: " + parser.getName());
}
}
-
+
return interpolator;
}
diff --git a/core/java/android/view/animation/AnticipateInterpolator.java b/core/java/android/view/animation/AnticipateInterpolator.java
index 83a8007..fe756bd 100644
--- a/core/java/android/view/animation/AnticipateInterpolator.java
+++ b/core/java/android/view/animation/AnticipateInterpolator.java
@@ -17,9 +17,12 @@
package android.view.animation;
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.content.res.Resources.Theme;
import android.util.AttributeSet;
+import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
@@ -45,11 +48,20 @@
}
public AnticipateInterpolator(Context context, AttributeSet attrs) {
- TypedArray a = context.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.AnticipateInterpolator);
+ this(context.getResources(), context.getTheme(), attrs);
+ }
+
+ /** @hide */
+ public AnticipateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.AnticipateInterpolator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, R.styleable.AnticipateInterpolator);
+ }
mTension =
- a.getFloat(com.android.internal.R.styleable.AnticipateInterpolator_tension, 2.0f);
+ a.getFloat(R.styleable.AnticipateInterpolator_tension, 2.0f);
a.recycle();
}
diff --git a/core/java/android/view/animation/AnticipateOvershootInterpolator.java b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
index 1a8adfd..78e5acf 100644
--- a/core/java/android/view/animation/AnticipateOvershootInterpolator.java
+++ b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
@@ -17,6 +17,8 @@
package android.view.animation;
import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.util.AttributeSet;
@@ -62,7 +64,17 @@
}
public AnticipateOvershootInterpolator(Context context, AttributeSet attrs) {
- TypedArray a = context.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator);
+ this(context.getResources(), context.getTheme(), attrs);
+ }
+
+ /** @hide */
+ public AnticipateOvershootInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, AnticipateOvershootInterpolator);
+ }
mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) *
a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f);
diff --git a/core/java/android/view/animation/CycleInterpolator.java b/core/java/android/view/animation/CycleInterpolator.java
index d1ebf05..3114aa3 100644
--- a/core/java/android/view/animation/CycleInterpolator.java
+++ b/core/java/android/view/animation/CycleInterpolator.java
@@ -17,9 +17,12 @@
package android.view.animation;
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.content.res.Resources.Theme;
import android.util.AttributeSet;
+import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
@@ -34,20 +37,29 @@
public CycleInterpolator(float cycles) {
mCycles = cycles;
}
-
+
public CycleInterpolator(Context context, AttributeSet attrs) {
- TypedArray a =
- context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.CycleInterpolator);
-
- mCycles = a.getFloat(com.android.internal.R.styleable.CycleInterpolator_cycles, 1.0f);
-
+ this(context.getResources(), context.getTheme(), attrs);
+ }
+
+ /** @hide */
+ public CycleInterpolator(Resources resources, Theme theme, AttributeSet attrs) {
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.CycleInterpolator, 0, 0);
+ } else {
+ a = resources.obtainAttributes(attrs, R.styleable.CycleInterpolator);
+ }
+
+ mCycles = a.getFloat(R.styleable.CycleInterpolator_cycles, 1.0f);
+
a.recycle();
}
-
+
public float getInterpolation(float input) {
return (float)(Math.sin(2 * mCycles * Math.PI * input));
}
-
+
private float mCycles;
/** @hide */
diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java
index 0789a0e..674207c 100644
--- a/core/java/android/view/animation/DecelerateInterpolator.java
+++ b/core/java/android/view/animation/DecelerateInterpolator.java
@@ -17,15 +17,18 @@
package android.view.animation;
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.content.res.Resources.Theme;
import android.util.AttributeSet;
+import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
- * An interpolator where the rate of change starts out quickly and
+ * An interpolator where the rate of change starts out quickly and
* and then decelerates.
*
*/
@@ -36,7 +39,7 @@
/**
* Constructor
- *
+ *
* @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces
* an upside-down y=x^2 parabola. Increasing factor above 1.0f makes exaggerates the
* ease-out effect (i.e., it starts even faster and ends evens slower)
@@ -44,16 +47,25 @@
public DecelerateInterpolator(float factor) {
mFactor = factor;
}
-
+
public DecelerateInterpolator(Context context, AttributeSet attrs) {
- TypedArray a =
- context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.DecelerateInterpolator);
-
- mFactor = a.getFloat(com.android.internal.R.styleable.DecelerateInterpolator_factor, 1.0f);
-
+ this(context.getResources(), context.getTheme(), attrs);
+ }
+
+ /** @hide */
+ public DecelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.DecelerateInterpolator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, R.styleable.DecelerateInterpolator);
+ }
+
+ mFactor = a.getFloat(R.styleable.DecelerateInterpolator_factor, 1.0f);
+
a.recycle();
}
-
+
public float getInterpolation(float input) {
float result;
if (mFactor == 1.0f) {
@@ -63,7 +75,7 @@
}
return result;
}
-
+
private float mFactor = 1.0f;
/** @hide */
diff --git a/core/java/android/view/animation/OvershootInterpolator.java b/core/java/android/view/animation/OvershootInterpolator.java
index a2466f1..d6c2808 100644
--- a/core/java/android/view/animation/OvershootInterpolator.java
+++ b/core/java/android/view/animation/OvershootInterpolator.java
@@ -17,9 +17,12 @@
package android.view.animation;
import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
@@ -46,11 +49,20 @@
}
public OvershootInterpolator(Context context, AttributeSet attrs) {
- TypedArray a = context.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.OvershootInterpolator);
+ this(context.getResources(), context.getTheme(), attrs);
+ }
+
+ /** @hide */
+ public OvershootInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.OvershootInterpolator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, R.styleable.OvershootInterpolator);
+ }
mTension =
- a.getFloat(com.android.internal.R.styleable.OvershootInterpolator_tension, 2.0f);
+ a.getFloat(R.styleable.OvershootInterpolator_tension, 2.0f);
a.recycle();
}
diff --git a/core/java/android/view/animation/PathInterpolator.java b/core/java/android/view/animation/PathInterpolator.java
index a369509..da12ffb 100644
--- a/core/java/android/view/animation/PathInterpolator.java
+++ b/core/java/android/view/animation/PathInterpolator.java
@@ -16,11 +16,15 @@
package android.view.animation;
import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.InflateException;
+import com.android.internal.R;
+
/**
* An interpolator that can traverse a Path that extends from <code>Point</code>
* <code>(0, 0)</code> to <code>(1, 1)</code>. The x coordinate along the <code>Path</code>
@@ -81,18 +85,33 @@
}
public PathInterpolator(Context context, AttributeSet attrs) {
- TypedArray a = context.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.PathInterpolator);
- if (!a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlX1)) {
+ this(context.getResources(), context.getTheme(), attrs);
+ }
+
+ /** @hide */
+ public PathInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.PathInterpolator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, R.styleable.PathInterpolator);
+ }
+ parseInterpolatorFromTypeArray(a);
+
+ a.recycle();
+ }
+
+ private void parseInterpolatorFromTypeArray(TypedArray a) {
+ if (!a.hasValue(R.styleable.PathInterpolator_controlX1)) {
throw new InflateException("pathInterpolator requires the controlX1 attribute");
- } else if (!a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlY1)) {
+ } else if (!a.hasValue(R.styleable.PathInterpolator_controlY1)) {
throw new InflateException("pathInterpolator requires the controlY1 attribute");
}
- float x1 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlX1, 0);
- float y1 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlY1, 0);
+ float x1 = a.getFloat(R.styleable.PathInterpolator_controlX1, 0);
+ float y1 = a.getFloat(R.styleable.PathInterpolator_controlY1, 0);
- boolean hasX2 = a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlX2);
- boolean hasY2 = a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlY2);
+ boolean hasX2 = a.hasValue(R.styleable.PathInterpolator_controlX2);
+ boolean hasY2 = a.hasValue(R.styleable.PathInterpolator_controlY2);
if (hasX2 != hasY2) {
throw new InflateException(
@@ -102,12 +121,10 @@
if (!hasX2) {
initQuad(x1, y1);
} else {
- float x2 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlX2, 0);
- float y2 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlY2, 0);
+ float x2 = a.getFloat(R.styleable.PathInterpolator_controlX2, 0);
+ float y2 = a.getFloat(R.styleable.PathInterpolator_controlY2, 0);
initCubic(x1, y1, x2, y2);
}
-
- a.recycle();
}
private void initQuad(float controlX, float controlY) {
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index a74e3a0..e1f40b7 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -195,6 +195,7 @@
public boolean commitText(CharSequence text, int newCursorPosition) {
if (DEBUG) Log.v(TAG, "commitText " + text);
replaceText(text, newCursorPosition, false);
+ mIMM.notifyUserAction();
sendCurrentText();
return true;
}
@@ -435,6 +436,7 @@
public boolean setComposingText(CharSequence text, int newCursorPosition) {
if (DEBUG) Log.v(TAG, "setComposingText " + text);
replaceText(text, newCursorPosition, true);
+ mIMM.notifyUserAction();
return true;
}
@@ -518,6 +520,7 @@
viewRootImpl.dispatchKeyFromIme(event);
}
}
+ mIMM.notifyUserAction();
return false;
}
@@ -601,9 +604,6 @@
}
beginBatchEdit();
- if (!composing && !TextUtils.isEmpty(text)) {
- mIMM.notifyUserAction();
- }
// delete composing text set previously.
int a = getComposingSpanStart(content);
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index fad6747..66f5f6c 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -186,12 +186,12 @@
/**
* Builder for {@link CursorAnchorInfo}. This class is not designed to be thread-safe.
*/
- public static final class CursorAnchorInfoBuilder {
+ public static final class Builder {
/**
* Sets the text range of the selection. Calling this can be skipped if there is no
* selection.
*/
- public CursorAnchorInfoBuilder setSelectionRange(final int newStart, final int newEnd) {
+ public Builder setSelectionRange(final int newStart, final int newEnd) {
mSelectionStart = newStart;
mSelectionEnd = newEnd;
return this;
@@ -205,8 +205,7 @@
* @param index index where the composing text starts.
* @param composingText the entire composing text.
*/
- public CursorAnchorInfoBuilder setComposingText(final int index,
- final CharSequence composingText) {
+ public Builder setComposingText(final int index, final CharSequence composingText) {
mComposingTextStart = index;
if (composingText == null) {
mComposingText = null;
@@ -236,9 +235,8 @@
* that will be transformed with the transformation matrix when rendered on the screen. This
* should be calculated or compatible with {@link Layout#getLineBottom(int)}.
*/
- public CursorAnchorInfoBuilder setInsertionMarkerLocation(
- final float horizontalPosition, final float lineTop, final float lineBaseline,
- final float lineBottom){
+ public Builder setInsertionMarkerLocation(final float horizontalPosition,
+ final float lineTop, final float lineBaseline, final float lineBottom){
mInsertionMarkerHorizontal = horizontalPosition;
mInsertionMarkerTop = lineTop;
mInsertionMarkerBaseline = lineBaseline;
@@ -269,9 +267,8 @@
* @throws IllegalArgumentException If the index is a negative value, or not greater than
* all of the previously called indices.
*/
- public CursorAnchorInfoBuilder addCharacterRect(final int index,
- final float leadingEdgeX, final float leadingEdgeY, final float trailingEdgeX,
- final float trailingEdgeY) {
+ public Builder addCharacterRect(final int index, final float leadingEdgeX,
+ final float leadingEdgeY, final float trailingEdgeX, final float trailingEdgeY) {
if (index < 0) {
throw new IllegalArgumentException("index must not be a negative integer.");
}
@@ -289,7 +286,7 @@
* @param matrix transformation matrix from local coordinates into screen coordinates. null
* is interpreted as an identity matrix.
*/
- public CursorAnchorInfoBuilder setMatrix(final Matrix matrix) {
+ public Builder setMatrix(final Matrix matrix) {
mMatrix.set(matrix != null ? matrix : Matrix.IDENTITY_MATRIX);
return this;
}
@@ -297,7 +294,7 @@
/**
* @return {@link CursorAnchorInfo} using parameters in this
- * {@link CursorAnchorInfoBuilder}.
+ * {@link Builder}.
*/
public CursorAnchorInfo build() {
return new CursorAnchorInfo(this);
@@ -323,7 +320,7 @@
}
}
- private CursorAnchorInfo(final CursorAnchorInfoBuilder builder) {
+ private CursorAnchorInfo(final Builder builder) {
mSelectionStart = builder.mSelectionStart;
mSelectionEnd = builder.mSelectionEnd;
mComposingTextStart = builder.mComposingTextStart;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 0693617..ace8808 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -320,6 +320,25 @@
int mCursorCandEnd;
/**
+ * Represents an invalid action notification sequence number. {@link InputMethodManagerService}
+ * always issues a positive integer for action notification sequence numbers. Thus -1 is
+ * guaranteed to be different from any valid sequence number.
+ */
+ private static final int NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER = -1;
+ /**
+ * The next sequence number that is to be sent to {@link InputMethodManagerService} via
+ * {@link IInputMethodManager#notifyUserAction(int)} at once when a user action is observed.
+ */
+ private int mNextUserActionNotificationSequenceNumber =
+ NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER;
+
+ /**
+ * The last sequence number that is already sent to {@link InputMethodManagerService}.
+ */
+ private int mLastSentUserActionNotificationSequenceNumber =
+ NOT_AN_ACTION_NOTIFICATION_SEQUENCE_NUMBER;
+
+ /**
* The instance that has previously been sent to the input method.
*/
private CursorAnchorInfo mCursorAnchorInfo = null;
@@ -364,6 +383,7 @@
static final int MSG_TIMEOUT_INPUT_EVENT = 6;
static final int MSG_FLUSH_INPUT_EVENT = 7;
static final int MSG_SET_CURSOR_ANCHOR_MONITOR_MODE = 8;
+ static final int MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER = 9;
class H extends Handler {
H(Looper looper) {
@@ -503,6 +523,11 @@
}
return;
}
+ case MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER: {
+ synchronized (mH) {
+ mNextUserActionNotificationSequenceNumber = msg.arg1;
+ }
+ }
}
}
}
@@ -572,6 +597,12 @@
public void setCursorAnchorMonitorMode(int monitorMode) {
mH.sendMessage(mH.obtainMessage(MSG_SET_CURSOR_ANCHOR_MONITOR_MODE, monitorMode, 0));
}
+
+ @Override
+ public void setUserActionNotificationSequenceNumber(int sequenceNumber) {
+ mH.sendMessage(mH.obtainMessage(MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER,
+ sequenceNumber, 0));
+ }
};
final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
@@ -1214,6 +1245,8 @@
mBindSequence = res.sequence;
mCurMethod = res.method;
mCurId = res.id;
+ mNextUserActionNotificationSequenceNumber =
+ res.userActionNotificationSequenceNumber;
} else {
if (res.channel != null && res.channel != mCurChannel) {
res.channel.dispose();
@@ -1918,8 +1951,28 @@
*/
public void notifyUserAction() {
synchronized (mH) {
+ if (mLastSentUserActionNotificationSequenceNumber ==
+ mNextUserActionNotificationSequenceNumber) {
+ if (DEBUG) {
+ Log.w(TAG, "Ignoring notifyUserAction as it has already been sent."
+ + " mLastSentUserActionNotificationSequenceNumber: "
+ + mLastSentUserActionNotificationSequenceNumber
+ + " mNextUserActionNotificationSequenceNumber: "
+ + mNextUserActionNotificationSequenceNumber);
+ }
+ return;
+ }
try {
- mService.notifyUserAction();
+ if (DEBUG) {
+ Log.w(TAG, "notifyUserAction: "
+ + " mLastSentUserActionNotificationSequenceNumber: "
+ + mLastSentUserActionNotificationSequenceNumber
+ + " mNextUserActionNotificationSequenceNumber: "
+ + mNextUserActionNotificationSequenceNumber);
+ }
+ mService.notifyUserAction(mNextUserActionNotificationSequenceNumber);
+ mLastSentUserActionNotificationSequenceNumber =
+ mNextUserActionNotificationSequenceNumber;
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId, e);
}
@@ -2103,6 +2156,10 @@
+ " mCursorSelEnd=" + mCursorSelEnd
+ " mCursorCandStart=" + mCursorCandStart
+ " mCursorCandEnd=" + mCursorCandEnd);
+ p.println(" mNextUserActionNotificationSequenceNumber="
+ + mNextUserActionNotificationSequenceNumber
+ + " mLastSentUserActionNotificationSequenceNumber="
+ + mLastSentUserActionNotificationSequenceNumber);
}
/**
diff --git a/core/java/android/webkit/ClientCertRequest.java b/core/java/android/webkit/ClientCertRequest.java
index 588b868..4a7f5fd 100644
--- a/core/java/android/webkit/ClientCertRequest.java
+++ b/core/java/android/webkit/ClientCertRequest.java
@@ -27,7 +27,7 @@
* such as the host name and the port number requesting the cert, the acceptable
* key types and the principals.
*
- * The user should call one of the interface methods to indicate how to deal
+ * The user should call one of the class methods to indicate how to deal
* with the client certificate request. All methods should be called on
* UI thread.
*
@@ -37,42 +37,45 @@
* {@link WebView#clearClientCertPreferences}.
*
*/
-public interface ClientCertRequest {
+public abstract class ClientCertRequest {
+
+ public ClientCertRequest() { }
+
/**
* Returns the acceptable types of asymmetric keys (can be null).
*/
- public String[] getKeyTypes();
+ public abstract String[] getKeyTypes();
/**
* Returns the acceptable certificate issuers for the certificate
* matching the private key (can be null).
*/
- public Principal[] getPrincipals();
+ public abstract Principal[] getPrincipals();
/**
* Returns the host name of the server requesting the certificate.
*/
- public String getHost();
+ public abstract String getHost();
/**
* Returns the port number of the server requesting the certificate.
*/
- public int getPort();
+ public abstract int getPort();
/**
* Proceed with the specified private key and client certificate chain.
* Remember the user's positive choice and use it for future requests.
*/
- public void proceed(PrivateKey privateKey, X509Certificate[] chain);
+ public abstract void proceed(PrivateKey privateKey, X509Certificate[] chain);
/**
* Ignore the request for now. Do not remember user's choice.
*/
- public void ignore();
+ public abstract void ignore();
/**
* Cancel this request. Remember the user's choice and use it for
* future requests.
*/
- public void cancel();
+ public abstract void cancel();
}
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index abed082..321d9d3 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.net.WebAddress;
+import android.webkit.ValueCallback;
/**
* Manages the cookies used by an application's {@link WebView} instances.
@@ -72,7 +73,7 @@
* path and name will be replaced with the new cookie. The cookie being set
* will be ignored if it is expired.
*
- * @param url the URL for which the cookie is set
+ * @param url the URL for which the cookie is to be set
* @param value the cookie as a string, using the format of the 'Set-Cookie'
* HTTP response header
*/
@@ -81,6 +82,29 @@
}
/**
+ * Sets a cookie for the given URL. Any existing cookie with the same host,
+ * path and name will be replaced with the new cookie. The cookie being set
+ * will be ignored if it is expired.
+ * <p>
+ * This method is asynchronous.
+ * If a {@link ValueCallback} is provided,
+ * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current
+ * thread's {@link android.os.Looper} once the operation is complete.
+ * The value provided to the callback indicates whether the cookie was set successfully.
+ * You can pass {@code null} as the callback if you don't need to know when the operation
+ * completes or whether it succeeded, and in this case it is safe to call the method from a
+ * thread without a Looper.
+ *
+ * @param url the URL for which the cookie is to be set
+ * @param value the cookie as a string, using the format of the 'Set-Cookie'
+ * HTTP response header
+ * @param callback a callback to be executed when the cookie has been set
+ */
+ public void setCookie(String url, String value, ValueCallback<Boolean> callback) {
+ throw new MustOverrideException();
+ }
+
+ /**
* Gets the cookies for the given URL.
*
* @param url the URL for which the cookies are requested
@@ -120,19 +144,57 @@
/**
* Removes all session cookies, which are cookies without an expiration
* date.
+ * @deprecated use {@link #removeSessionCookies(ValueCallback)} instead.
*/
public void removeSessionCookie() {
throw new MustOverrideException();
}
/**
- * Removes all cookies.
+ * Removes all session cookies, which are cookies without an expiration
+ * date.
+ * <p>
+ * This method is asynchronous.
+ * If a {@link ValueCallback} is provided,
+ * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current
+ * thread's {@link android.os.Looper} once the operation is complete.
+ * The value provided to the callback indicates whether any cookies were removed.
+ * You can pass {@code null} as the callback if you don't need to know when the operation
+ * completes or whether any cookie were removed, and in this case it is safe to call the
+ * method from a thread without a Looper.
+ * @param callback a callback which is executed when the session cookies have been removed
*/
+ public void removeSessionCookies(ValueCallback<Boolean> callback) {
+ throw new MustOverrideException();
+ }
+
+ /**
+ * Removes all cookies.
+ * @deprecated Use {@link #removeAllCookies(ValueCallback)} instead.
+ */
+ @Deprecated
public void removeAllCookie() {
throw new MustOverrideException();
}
/**
+ * Removes all cookies.
+ * <p>
+ * This method is asynchronous.
+ * If a {@link ValueCallback} is provided,
+ * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current
+ * thread's {@link android.os.Looper} once the operation is complete.
+ * The value provided to the callback indicates whether any cookies were removed.
+ * You can pass {@code null} as the callback if you don't need to know when the operation
+ * completes or whether any cookies were removed, and in this case it is safe to call the
+ * method from a thread without a Looper.
+ * @param callback a callback which is executed when the cookies have been removed
+ */
+ public void removeAllCookies(ValueCallback<Boolean> callback) {
+ throw new MustOverrideException();
+ }
+
+ /**
* Gets whether there are stored cookies.
*
* @return true if there are stored cookies
@@ -153,7 +215,9 @@
/**
* Removes all expired cookies.
+ * @deprecated The WebView handles removing expired cookies automatically.
*/
+ @Deprecated
public void removeExpiredCookie() {
throw new MustOverrideException();
}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index d630a9a..470d413 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -92,7 +92,7 @@
@Deprecated
public void onShowCustomView(View view, int requestedOrientation,
CustomViewCallback callback) {};
-
+
/**
* Notify the host application that the current page would
* like to hide its custom view.
@@ -392,6 +392,75 @@
}
/**
+ * Tell the client to show a file chooser.
+ *
+ * This is called to handle HTML forms with 'file' input type, in response to the
+ * user pressing the "Select File" button.
+ * To cancel the request, call <code>filePathCallback.onReceiveValue(null)</code> and
+ * return true.
+ *
+ * @param webView The WebView instance that is initiating the request.
+ * @param filePathCallback Invoke this callback to supply the list of paths to files to upload,
+ * or NULL to cancel. Must only be called if the
+ * <code>showFileChooser</code> implementations returns true.
+ * @param fileChooserParams Describes the mode of file chooser to be opened, and options to be
+ * used with it.
+ * @return true if filePathCallback will be invoked, false to use default handling.
+ *
+ * @see FileChooserParams
+ */
+ public boolean showFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
+ FileChooserParams fileChooserParams) {
+ return false;
+ }
+
+ /**
+ * Parameters used in the {@link #showFileChooser} method.
+ * This is intended to be used as a read-only data struct by the application.
+ */
+ public static class FileChooserParams {
+ // Flags for mode
+ /** Bitflag for <code>mode</code> indicating multiple files maybe selected */
+ public static final int MODE_OPEN_MULTIPLE = 1 << 0;
+ /** Bitflag for <code>mode</code> indicating a folder maybe selected.
+ * The implementation should enumerate all files selected by this operation */
+ public static final int MODE_OPEN_FOLDER = 1 << 1;
+ /** Bitflag for <code>mode</code> indicating a non-existant filename maybe returned */
+ public static final int MODE_SAVE = 1 << 2;
+
+ /**
+ * Bit-field of the <code>MODE_</code> flags.
+ *
+ * 0 indicates plain single file open.
+ */
+ public int mode;
+
+ /**
+ * Comma-seperated list of acceptable MIME types.
+ */
+ public String acceptTypes;
+
+ /**
+ * true indicates a preference for a live media captured value (e.g. Camera, Microphone).
+ *
+ * Use <code>acceptTypes</code> to determine suitable capture devices.
+ */
+ public boolean capture;
+
+ /**
+ * The title to use for this file selector, or null.
+ *
+ * Maybe null, in which case a default title should be used.
+ */
+ public String title;
+
+ /**
+ * Name of a default selection if appropriate, or null.
+ */
+ public String defaultFilename;
+ };
+
+ /**
* Tell the client to open a file chooser.
* @param uploadFile A ValueCallback to set the URI of the file to upload.
* onReceiveValue must be called to wake up the thread.a
@@ -399,8 +468,11 @@
* associated with this file picker.
* @param capture The value of the 'capture' attribute of the input tag
* associated with this file picker.
- * @hide
+ *
+ * @deprecated Use {@link #showFileChooser} instead.
+ * @hide This method was not published in any SDK version.
*/
+ @Deprecated
public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture) {
uploadFile.onReceiveValue(null);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 91ca7b4..482c7e8 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1486,11 +1486,11 @@
}
/**
- * Clears the client certificate preferences table stored in response
- * to proceeding/cancelling client cert requests. Note that webview
+ * Clears the client certificate preferences stored in response
+ * to proceeding/cancelling client cert requests. Note that Webview
* automatically clears these preferences when it receives a
- * {@link KeyChain#ACTION_STORAGE_CHANGED} intent. The client certificate
- * preferences are global for all Webviews.
+ * {@link KeyChain#ACTION_STORAGE_CHANGED} intent. The preferences are
+ * shared by all the webviews that are created by the embedder application.
*
* @param onCleared A runnable to be invoked when client certs are cleared.
* The embedder can pass null if not interested in the
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 43f623b..eb3f882 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -16,11 +16,15 @@
package android.widget;
+import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Insets;
+import android.graphics.PorterDuff;
import android.graphics.Rect;
+import android.graphics.PorterDuff.Mode;
import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -31,10 +35,16 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import com.android.internal.R;
+
public abstract class AbsSeekBar extends ProgressBar {
private final Rect mTempRect = new Rect();
private Drawable mThumb;
+ private ColorStateList mThumbTint = null;
+ private PorterDuff.Mode mThumbTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasThumbTint = false;
+
private int mThumbOffset;
private boolean mSplitTrack;
@@ -83,6 +93,15 @@
final Drawable thumb = a.getDrawable(com.android.internal.R.styleable.SeekBar_thumb);
setThumb(thumb);
+ if (a.hasValue(R.styleable.SeekBar_thumbTint)) {
+ mThumbTint = a.getColorStateList(R.styleable.SeekBar_thumbTint);
+ mThumbTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.SeekBar_thumbTintMode, -1), mThumbTintMode);
+ mHasThumbTint = true;
+
+ applyThumbTint();
+ }
+
// Guess thumb offset if thumb != null, but allow layout to override.
final int thumbOffset = a.getDimensionPixelOffset(
com.android.internal.R.styleable.SeekBar_thumbOffset, getThumbOffset());
@@ -108,7 +127,7 @@
* @param thumb Drawable representing the thumb
*/
public void setThumb(Drawable thumb) {
- boolean needUpdate;
+ final boolean needUpdate;
// This way, calling setThumb again with the same bitmap will result in
// it recalcuating mThumbOffset (if for example it the bounds of the
// drawable changed)
@@ -118,6 +137,7 @@
} else {
needUpdate = false;
}
+
if (thumb != null) {
thumb.setCallback(this);
if (canResolveLayoutDirection()) {
@@ -136,8 +156,12 @@
requestLayout();
}
}
+
mThumb = thumb;
+
+ applyThumbTint();
invalidate();
+
if (needUpdate) {
updateThumbAndTrackPos(getWidth(), getHeight());
if (thumb != null && thumb.isStateful()) {
@@ -160,6 +184,88 @@
}
/**
+ * Applies a tint to the thumb drawable.
+ * <p>
+ * Subsequent calls to {@link #setThumb(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#SeekBar_thumbTint
+ * @attr ref android.R.styleable#SeekBar_thumbTintMode
+ * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+ */
+ private void setThumbTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mThumbTint = tint;
+ mThumbTintMode = tintMode;
+ mHasThumbTint = true;
+
+ applyThumbTint();
+ }
+
+ /**
+ * Applies a tint to the thumb drawable. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setThumb(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#SeekBar_thumbTint
+ * @see #setThumbTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setThumbTint(@Nullable ColorStateList tint) {
+ setThumbTint(tint, mThumbTintMode);
+ }
+
+ /**
+ * @return the tint applied to the thumb drawable
+ * @attr ref android.R.styleable#SeekBar_thumbTint
+ * @see #setThumbTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getThumbTint() {
+ return mThumbTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setThumbTint(ColorStateList)}} to the thumb drawable. The
+ * default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#SeekBar_thumbTintMode
+ * @see #setThumbTint(ColorStateList)
+ */
+ public void setThumbTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setThumbTint(mThumbTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the thumb drawable
+ * @attr ref android.R.styleable#SeekBar_thumbTintMode
+ * @see #setThumbTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getThumbTintMode() {
+ return mThumbTintMode;
+ }
+
+ private void applyThumbTint() {
+ if (mThumb != null && mHasThumbTint) {
+ mThumb = mThumb.mutate();
+ mThumb.setTint(mThumbTint, mThumbTintMode);
+ }
+ }
+
+ /**
* @see #setThumbOffset(int)
*/
public int getThumbOffset() {
@@ -255,6 +361,22 @@
}
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ final Drawable progressDrawable = getProgressDrawable();
+ if (progressDrawable != null) {
+ progressDrawable.setHotspot(x, y);
+ }
+
+ final Drawable thumb = mThumb;
+ if (thumb != null) {
+ thumb.setHotspot(x, y);
+ }
+ }
+
@Override
public void invalidateDrawable(Drawable dr) {
super.invalidateDrawable(dr);
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 3ae9508..7113793 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -307,6 +307,16 @@
}
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ if (mCheckMarkDrawable != null) {
+ mCheckMarkDrawable.setHotspot(x, y);
+ }
+ }
+
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 6aff4f4..747d2b1 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -16,11 +16,15 @@
package android.widget;
+import android.annotation.Nullable;
+import android.graphics.PorterDuff;
import com.android.internal.R;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -48,7 +52,12 @@
private boolean mChecked;
private int mButtonResource;
private boolean mBroadcasting;
+
private Drawable mButtonDrawable;
+ private ColorStateList mButtonTint = null;
+ private PorterDuff.Mode mButtonTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasButtonTint = false;
+
private OnCheckedChangeListener mOnCheckedChangeListener;
private OnCheckedChangeListener mOnCheckedChangeWidgetListener;
@@ -74,13 +83,22 @@
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.CompoundButton, defStyleAttr, defStyleRes);
- Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
+ final Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
if (d != null) {
setButtonDrawable(d);
}
- boolean checked = a
- .getBoolean(com.android.internal.R.styleable.CompoundButton_checked, false);
+ if (a.hasValue(R.styleable.CompoundButton_buttonTint)) {
+ mButtonTint = a.getColorStateList(R.styleable.CompoundButton_buttonTint);
+ mButtonTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.CompoundButton_buttonTintMode, -1), mButtonTintMode);
+ mHasButtonTint = true;
+
+ applyButtonTint();
+ }
+
+ final boolean checked = a.getBoolean(
+ com.android.internal.R.styleable.CompoundButton_checked, false);
setChecked(checked);
a.recycle();
@@ -173,9 +191,11 @@
}
/**
- * Set the background to a given Drawable, identified by its resource id.
+ * Set the button graphic to a given Drawable, identified by its resource
+ * id.
*
- * @param resid the resource id of the drawable to use as the background
+ * @param resid the resource id of the drawable to use as the button
+ * graphic
*/
public void setButtonDrawable(int resid) {
if (resid != 0 && resid == mButtonResource) {
@@ -192,23 +212,114 @@
}
/**
- * Set the background to a given Drawable
+ * Set the button graphic to a given Drawable
*
- * @param d The Drawable to use as the background
+ * @param d The Drawable to use as the button graphic
*/
public void setButtonDrawable(Drawable d) {
- if (d != null) {
+ if (mButtonDrawable != d) {
if (mButtonDrawable != null) {
mButtonDrawable.setCallback(null);
unscheduleDrawable(mButtonDrawable);
}
- d.setCallback(this);
- d.setVisible(getVisibility() == VISIBLE, false);
- mButtonDrawable = d;
- setMinHeight(mButtonDrawable.getIntrinsicHeight());
- }
- refreshDrawableState();
+ mButtonDrawable = d;
+
+ if (d != null) {
+ d.setCallback(this);
+ d.setLayoutDirection(getLayoutDirection());
+ if (d.isStateful()) {
+ d.setState(getDrawableState());
+ }
+ d.setVisible(getVisibility() == VISIBLE, false);
+ setMinHeight(d.getIntrinsicHeight());
+ applyButtonTint();
+ }
+ }
+ }
+
+ /**
+ * Applies a tint to the button drawable.
+ * <p>
+ * Subsequent calls to {@link #setButtonDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and tint
+ * mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#CompoundButton_buttonTint
+ * @attr ref android.R.styleable#CompoundButton_buttonTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setButtonTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mButtonTint = tint;
+ mButtonTintMode = tintMode;
+ mHasButtonTint = true;
+
+ applyButtonTint();
+ }
+
+ /**
+ * Applies a tint to the button drawable. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setButtonDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and tint
+ * mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#CompoundButton_buttonTint
+ * @see #setButtonTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ public void setButtonTint(@Nullable ColorStateList tint) {
+ setButtonTint(tint, mButtonTintMode);
+ }
+
+ /**
+ * @return the tint applied to the button drawable
+ * @attr ref android.R.styleable#CompoundButton_buttonTint
+ * @see #setButtonTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getButtonTint() {
+ return mButtonTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setButtonTint(ColorStateList)}} to the button drawable. The
+ * default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#CompoundButton_buttonTintMode
+ * @see #setButtonTint(ColorStateList)
+ */
+ public void setButtonTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setButtonTint(mButtonTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the button drawable
+ * @attr ref android.R.styleable#CompoundButton_buttonTintMode
+ * @see #setButtonTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getButtonTintMode() {
+ return mButtonTintMode;
+ }
+
+ private void applyButtonTint() {
+ if (mButtonDrawable != null && mHasButtonTint) {
+ mButtonDrawable = mButtonDrawable.mutate();
+ mButtonDrawable.setTint(mButtonTint, mButtonTintMode);
+ }
}
@Override
@@ -320,6 +431,16 @@
}
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ if (mButtonDrawable != null) {
+ mButtonDrawable.setHotspot(x, y);
+ }
+ }
+
@Override
protected boolean verifyDrawable(Drawable who) {
return super.verifyDrawable(who) || who == mButtonDrawable;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 27d6b82..4467128 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -96,7 +96,6 @@
import android.view.WindowManager;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.CursorAnchorInfo;
-import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
@@ -3013,7 +3012,7 @@
* {@link InputMethodManager#isWatchingCursor(View)} returns false.
*/
private final class CursorAnchorInfoNotifier implements TextViewPositionListener {
- final CursorAnchorInfoBuilder mSelectionInfoBuilder = new CursorAnchorInfoBuilder();
+ final CursorAnchorInfo.Builder mSelectionInfoBuilder = new CursorAnchorInfo.Builder();
final int[] mTmpIntOffset = new int[2];
final Matrix mViewToScreenMatrix = new Matrix();
@@ -3037,7 +3036,7 @@
return;
}
- final CursorAnchorInfoBuilder builder = mSelectionInfoBuilder;
+ final CursorAnchorInfo.Builder builder = mSelectionInfoBuilder;
builder.reset();
final int selectionStart = mTextView.getSelectionStart();
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index b029328..5a14929 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -18,11 +18,15 @@
import java.util.ArrayList;
+import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
@@ -33,6 +37,8 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.RemoteViews.RemoteView;
+import com.android.internal.R;
+
/**
* FrameLayout is designed to block out an area on the screen to display
@@ -62,6 +68,9 @@
@ViewDebug.ExportedProperty(category = "drawing")
private Drawable mForeground;
+ private ColorStateList mForegroundTint = null;
+ private PorterDuff.Mode mForegroundTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasForegroundTint = false;
@ViewDebug.ExportedProperty(category = "padding")
private int mForegroundPaddingLeft = 0;
@@ -119,6 +128,15 @@
setMeasureAllChildren(true);
}
+ if (a.hasValue(R.styleable.FrameLayout_foregroundTint)) {
+ mForegroundTint = a.getColorStateList(R.styleable.FrameLayout_foregroundTint);
+ mForegroundTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.FrameLayout_foregroundTintMode, -1), mForegroundTintMode);
+ mHasForegroundTint = true;
+
+ applyForegroundTint();
+ }
+
mForegroundInPadding = a.getBoolean(
com.android.internal.R.styleable.FrameLayout_foregroundInsidePadding, true);
@@ -205,6 +223,16 @@
}
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(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},
@@ -221,32 +249,34 @@
* into account by ensuring that the children are inset to be placed
* inside of the padding area.
*
- * @param drawable The Drawable to be drawn on top of the children.
+ * @param d The Drawable to be drawn on top of the children.
*
* @attr ref android.R.styleable#FrameLayout_foreground
*/
- public void setForeground(Drawable drawable) {
- if (mForeground != drawable) {
+ public void setForeground(Drawable d) {
+ if (mForeground != d) {
if (mForeground != null) {
mForeground.setCallback(null);
unscheduleDrawable(mForeground);
}
- mForeground = drawable;
+ mForeground = d;
mForegroundPaddingLeft = 0;
mForegroundPaddingTop = 0;
mForegroundPaddingRight = 0;
mForegroundPaddingBottom = 0;
- if (drawable != null) {
+ if (d != null) {
setWillNotDraw(false);
- drawable.setCallback(this);
- if (drawable.isStateful()) {
- drawable.setState(getDrawableState());
+ d.setCallback(this);
+ d.setLayoutDirection(getLayoutDirection());
+ if (d.isStateful()) {
+ d.setState(getDrawableState());
}
+ applyForegroundTint();
if (mForegroundGravity == Gravity.FILL) {
Rect padding = new Rect();
- if (drawable.getPadding(padding)) {
+ if (d.getPadding(padding)) {
mForegroundPaddingLeft = padding.left;
mForegroundPaddingTop = padding.top;
mForegroundPaddingRight = padding.right;
@@ -271,6 +301,89 @@
return mForeground;
}
+ /**
+ * Applies a tint to the foreground drawable.
+ * <p>
+ * Subsequent calls to {@link #setForeground(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#FrameLayout_foregroundTint
+ * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
+ * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+ */
+ private void setForegroundTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mForegroundTint = tint;
+ mForegroundTintMode = tintMode;
+ mHasForegroundTint = true;
+
+ applyForegroundTint();
+ }
+
+ /**
+ * Applies a tint to the foreground drawable. Does not modify the current
+ * tint mode, which is {@link PorterDuff.Mode#SRC_ATOP} 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#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#FrameLayout_foregroundTint
+ * @see #setForegroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setForegroundTint(@Nullable ColorStateList tint) {
+ setForegroundTint(tint, mForegroundTintMode);
+ }
+
+ /**
+ * @return the tint applied to the foreground drawable
+ * @attr ref android.R.styleable#FrameLayout_foregroundTint
+ * @see #setForegroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getForegroundTint() {
+ return mForegroundTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setForegroundTint(ColorStateList)}} to the foreground drawable.
+ * The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @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 #setForegroundTint(ColorStateList)
+ */
+ public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setForegroundTint(mForegroundTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the foreground
+ * drawable
+ * @attr ref android.R.styleable#FrameLayout_foregroundTintMode
+ * @see #setForegroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getForegroundTintMode() {
+ return mForegroundTintMode;
+ }
+
+ private void applyForegroundTint() {
+ if (mForeground != null && mHasForegroundTint) {
+ mForeground = mForeground.mutate();
+ mForeground.setTint(mForegroundTint, mForegroundTintMode);
+ }
+ }
+
int getPaddingLeftWithForeground() {
return mForegroundInPadding ? Math.max(mPaddingLeft, mForegroundPaddingLeft) :
mPaddingLeft + mForegroundPaddingLeft;
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 572302a4..399e087 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -16,8 +16,10 @@
package android.widget;
+import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -30,6 +32,7 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Xfermode;
+import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -44,6 +47,8 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.RemoteViews.RemoteView;
+import com.android.internal.R;
+
import java.io.IOException;
import java.io.InputStream;
@@ -75,13 +80,18 @@
private int mMaxHeight = Integer.MAX_VALUE;
// these are applied to the drawable
- private ColorFilter mColorFilter;
+ private ColorFilter mColorFilter = null;
+ private boolean mHasColorFilter = false;
private Xfermode mXfermode;
private int mAlpha = 255;
private int mViewAlphaScale = 256;
private boolean mColorMod = false;
private Drawable mDrawable = null;
+ private ColorStateList mDrawableTint = null;
+ private PorterDuff.Mode mDrawableTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasDrawableTint = false;
+
private int[] mState = null;
private boolean mMergeState = false;
private int mLevel = 0;
@@ -154,17 +164,21 @@
setMaxHeight(a.getDimensionPixelSize(
com.android.internal.R.styleable.ImageView_maxHeight, Integer.MAX_VALUE));
- int index = a.getInt(com.android.internal.R.styleable.ImageView_scaleType, -1);
+ final int index = a.getInt(com.android.internal.R.styleable.ImageView_scaleType, -1);
if (index >= 0) {
setScaleType(sScaleTypeArray[index]);
}
- int tint = a.getInt(com.android.internal.R.styleable.ImageView_tint, 0);
- if (tint != 0) {
- setColorFilter(tint);
+ if (a.hasValue(R.styleable.ImageView_tint)) {
+ mDrawableTint = a.getColorStateList(R.styleable.ImageView_tint);
+ mDrawableTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ImageView_tintMode, -1), mDrawableTintMode);
+ mHasDrawableTint = true;
+
+ applyDrawableTint();
}
-
- int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);
+
+ final int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);
if (alpha != 255) {
setAlpha(alpha);
}
@@ -435,6 +449,88 @@
}
/**
+ * Applies a tint to the image drawable.
+ * <p>
+ * Subsequent calls to {@link #setImageDrawable(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ImageView_tint
+ * @attr ref android.R.styleable#ImageView_tintMode
+ * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+ */
+ private void setTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mDrawableTint = tint;
+ mDrawableTintMode = tintMode;
+ mHasDrawableTint = true;
+
+ applyDrawableTint();
+ }
+
+ /**
+ * Applies a tint to the image drawable. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setImageDrawable(Drawable)} will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ImageView_tint
+ * @see Drawable#setTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setTint(@Nullable ColorStateList tint) {
+ setTint(tint, mDrawableTintMode);
+ }
+
+ /**
+ * @return the tint applied to the image drawable
+ * @attr ref android.R.styleable#ImageView_tint
+ * @see #setTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getTint() {
+ return mDrawableTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setTint(ColorStateList)}} to the image drawable. The default
+ * mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ImageView_tintMode
+ * @see #setTint(ColorStateList)
+ */
+ public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setTint(mDrawableTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the image drawable
+ * @attr ref android.R.styleable#ImageView_tintMode
+ * @see #setTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getTintMode() {
+ return mDrawableTintMode;
+ }
+
+ private void applyDrawableTint() {
+ if (mDrawable != null && mHasDrawableTint) {
+ mDrawable = mDrawable.mutate();
+ mDrawable.setTint(mDrawableTint, mDrawableTintMode);
+ }
+ }
+
+ /**
* Sets a Bitmap as the content of this ImageView.
*
* @param bm The bitmap to set
@@ -709,17 +805,20 @@
mDrawable.setCallback(null);
unscheduleDrawable(mDrawable);
}
+
mDrawable = d;
+
if (d != null) {
d.setCallback(this);
+ d.setLayoutDirection(getLayoutDirection());
if (d.isStateful()) {
d.setState(getDrawableState());
}
- d.setLevel(mLevel);
- d.setLayoutDirection(getLayoutDirection());
d.setVisible(getVisibility() == VISIBLE, true);
+ d.setLevel(mLevel);
mDrawableWidth = d.getIntrinsicWidth();
mDrawableHeight = d.getIntrinsicHeight();
+ applyDrawableTint();
applyColorMod();
configureBounds();
} else {
@@ -1010,7 +1109,17 @@
}
}
- @Override
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ if (mDrawable != null) {
+ mDrawable.setHotspot(x, y);
+ }
+ }
+
+ @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
@@ -1167,6 +1276,7 @@
public void setColorFilter(ColorFilter cf) {
if (mColorFilter != cf) {
mColorFilter = cf;
+ mHasColorFilter = true;
mColorMod = true;
applyColorMod();
invalidate();
@@ -1221,7 +1331,9 @@
// re-applied if the Drawable is changed.
if (mDrawable != null && mColorMod) {
mDrawable = mDrawable.mutate();
- mDrawable.setColorFilter(mColorFilter);
+ if (mHasColorFilter) {
+ mDrawable.setColorFilter(mColorFilter);
+ }
mDrawable.setXfermode(mXfermode);
mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
}
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index b49938c..62a8bec 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -16,13 +16,17 @@
package android.widget;
+import android.annotation.Nullable;
+import android.graphics.PorterDuff;
import com.android.internal.R;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
+import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.Animatable;
@@ -210,8 +214,26 @@
private Transformation mTransformation;
private AlphaAnimation mAnimation;
private boolean mHasAnimation;
+
private Drawable mIndeterminateDrawable;
+ private ColorStateList mIndeterminateTint = null;
+ private PorterDuff.Mode mIndeterminateTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasIndeterminateTint = false;
+
private Drawable mProgressDrawable;
+
+ private ColorStateList mProgressTint = null;
+ private PorterDuff.Mode mProgressTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasProgressTint = false;
+
+ private ColorStateList mProgressBackgroundTint = null;
+ private PorterDuff.Mode mProgressBackgroundTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasProgressBackgroundTint = false;
+
+ private ColorStateList mSecondaryProgressTint = null;
+ private PorterDuff.Mode mSecondaryProgressTintMode = PorterDuff.Mode.SRC_ATOP;
+ private boolean mHasSecondaryProgressTint = false;
+
private Drawable mCurrentDrawable;
Bitmap mSampleTile;
private boolean mNoInvalidate;
@@ -257,11 +279,11 @@
mNoInvalidate = true;
- Drawable drawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
- if (drawable != null) {
+ final Drawable progressDrawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
+ if (progressDrawable != null) {
// Calling this method can set mMaxHeight, make sure the corresponding
// XML attribute for mMaxHeight is read after calling this method
- setProgressDrawableTiled(drawable);
+ setProgressDrawableTiled(progressDrawable);
}
@@ -288,9 +310,10 @@
setSecondaryProgress(
a.getInt(R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
- drawable = a.getDrawable(R.styleable.ProgressBar_indeterminateDrawable);
- if (drawable != null) {
- setIndeterminateDrawableTiled(drawable);
+ final Drawable indeterminateDrawable = a.getDrawable(
+ R.styleable.ProgressBar_indeterminateDrawable);
+ if (indeterminateDrawable != null) {
+ setIndeterminateDrawableTiled(indeterminateDrawable);
}
mOnlyIndeterminate = a.getBoolean(
@@ -303,6 +326,53 @@
mMirrorForRtl = a.getBoolean(R.styleable.ProgressBar_mirrorForRtl, mMirrorForRtl);
+ if (a.hasValue(R.styleable.ProgressBar_progressTint)) {
+ mProgressTint = a.getColorStateList(
+ R.styleable.ProgressBar_progressTint);
+ mProgressTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ProgressBar_progressBackgroundTintMode, -1),
+ mProgressTintMode);
+ mHasProgressTint = true;
+
+ applyProgressLayerTint(R.id.progress, mProgressTint,
+ mProgressTintMode, true);
+ }
+
+ if (a.hasValue(R.styleable.ProgressBar_progressBackgroundTint)) {
+ mProgressBackgroundTint = a.getColorStateList(
+ R.styleable.ProgressBar_progressBackgroundTint);
+ mProgressBackgroundTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ProgressBar_progressTintMode, -1),
+ mProgressBackgroundTintMode);
+ mHasProgressBackgroundTint = true;
+
+ applyProgressLayerTint(R.id.background, mProgressBackgroundTint,
+ mProgressBackgroundTintMode, false);
+ }
+
+ if (a.hasValue(R.styleable.ProgressBar_secondaryProgressTint)) {
+ mSecondaryProgressTint = a.getColorStateList(
+ R.styleable.ProgressBar_secondaryProgressTint);
+ mSecondaryProgressTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ProgressBar_secondaryProgressTintMode, -1),
+ mSecondaryProgressTintMode);
+ mHasSecondaryProgressTint = true;
+
+ applyProgressLayerTint(R.id.secondaryProgress, mSecondaryProgressTint,
+ mSecondaryProgressTintMode, false);
+ }
+
+ if (a.hasValue(R.styleable.ProgressBar_indeterminateTint)) {
+ mIndeterminateTint = a.getColorStateList(
+ R.styleable.ProgressBar_indeterminateTint);
+ mIndeterminateTintMode = Drawable.parseTintMode(a.getInt(
+ R.styleable.ProgressBar_indeterminateTintMode, -1),
+ mIndeterminateTintMode);
+ mHasIndeterminateTint = true;
+
+ applyIndeterminateTint();
+ }
+
a.recycle();
// If not explicitly specified this view is important for accessibility.
@@ -479,16 +549,111 @@
* @see #setIndeterminate(boolean)
*/
public void setIndeterminateDrawable(Drawable d) {
- if (d != null) {
- d.setCallback(this);
+ if (mIndeterminateDrawable != d) {
+ if (mIndeterminateDrawable != null) {
+ mIndeterminateDrawable.setCallback(null);
+ unscheduleDrawable(mIndeterminateDrawable);
+ }
+
+ mIndeterminateDrawable = d;
+
+ if (d != null) {
+ d.setCallback(this);
+ d.setLayoutDirection(getLayoutDirection());
+ if (d.isStateful()) {
+ d.setState(getDrawableState());
+ }
+ applyIndeterminateTint();
+ }
+
+ if (mIndeterminate) {
+ mCurrentDrawable = d;
+ postInvalidate();
+ }
}
- mIndeterminateDrawable = d;
- if (mIndeterminateDrawable != null && canResolveLayoutDirection()) {
- mIndeterminateDrawable.setLayoutDirection(getLayoutDirection());
- }
- if (mIndeterminate) {
- mCurrentDrawable = d;
- postInvalidate();
+ }
+
+ /**
+ * Applies a tint to the indeterminate drawable.
+ * <p>
+ * Subsequent calls to {@link #setVisibilminateDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and
+ * tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTint
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setIndeterminateTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mIndeterminateTint = tint;
+ mIndeterminateTintMode = tintMode;
+ mHasIndeterminateTint = true;
+
+ applyIndeterminateTint();
+ }
+
+ /**
+ * Applies a tint to the indeterminate drawable. Does not modify the
+ * current tint mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * Subsequent calls to {@link #setIndeterminateDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and
+ * tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTint
+ * @see #setIndeterminateTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setIndeterminateTint(@Nullable ColorStateList tint) {
+ setIndeterminateTint(tint, mIndeterminateTintMode);
+ }
+
+ /**
+ * @return the tint applied to the indeterminate drawable
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTint
+ * @see #setIndeterminateTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getIndeterminateTint() {
+ return mIndeterminateTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setIndeterminateTint(ColorStateList)} to the indeterminate
+ * drawable. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
+ * @see #setIndeterminateTint(ColorStateList)
+ */
+ public void setIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setIndeterminateTint(mIndeterminateTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the indeterminate drawable
+ * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
+ * @see #setIndeterminateTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getIndeterminateTintMode() {
+ return mIndeterminateTintMode;
+ }
+
+ private void applyIndeterminateTint() {
+ if (mIndeterminateDrawable != null && mHasIndeterminateTint) {
+ mIndeterminateDrawable = mIndeterminateDrawable.mutate();
+ mIndeterminateDrawable.setTint(mIndeterminateTint, mIndeterminateTintMode);
}
}
@@ -532,42 +697,340 @@
* @see #setIndeterminate(boolean)
*/
public void setProgressDrawable(Drawable d) {
- boolean needUpdate;
- if (mProgressDrawable != null && d != mProgressDrawable) {
- mProgressDrawable.setCallback(null);
- needUpdate = true;
- } else {
- needUpdate = false;
- }
+ if (mProgressDrawable != d) {
+ if (mProgressDrawable != null) {
+ mProgressDrawable.setCallback(null);
+ unscheduleDrawable(mProgressDrawable);
+ }
- if (d != null) {
- d.setCallback(this);
- if (canResolveLayoutDirection()) {
+ mProgressDrawable = d;
+
+ if (d != null) {
+ d.setCallback(this);
d.setLayoutDirection(getLayoutDirection());
+ if (d.isStateful()) {
+ d.setState(getDrawableState());
+ }
+
+ // Make sure the ProgressBar is always tall enough
+ int drawableHeight = d.getMinimumHeight();
+ if (mMaxHeight < drawableHeight) {
+ mMaxHeight = drawableHeight;
+ requestLayout();
+ }
+
+ if (mHasProgressTint) {
+ applyProgressLayerTint(R.id.progress, mProgressTint, mProgressTintMode, true);
+ }
+
+ if (mHasProgressBackgroundTint) {
+ applyProgressLayerTint(R.id.background, mProgressBackgroundTint,
+ mProgressBackgroundTintMode, false);
+ }
+
+ if (mHasSecondaryProgressTint) {
+ applyProgressLayerTint(R.id.secondaryProgress, mSecondaryProgressTint,
+ mSecondaryProgressTintMode, false);
+ }
}
- // Make sure the ProgressBar is always tall enough
- int drawableHeight = d.getMinimumHeight();
- if (mMaxHeight < drawableHeight) {
- mMaxHeight = drawableHeight;
- requestLayout();
+ if (!mIndeterminate) {
+ mCurrentDrawable = d;
+ postInvalidate();
}
- }
- mProgressDrawable = d;
- if (!mIndeterminate) {
- mCurrentDrawable = d;
- postInvalidate();
- }
- if (needUpdate) {
updateDrawableBounds(getWidth(), getHeight());
updateDrawableState();
+
doRefreshProgress(R.id.progress, mProgress, false, false);
doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false);
}
}
/**
+ * Applies a tint to the progress indicator, if one exists, or to the
+ * entire progress drawable otherwise.
+ * <p>
+ * The progress indicator should be specified as a layer with
+ * id {@link android.R.id#progress} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and
+ * tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_progressTint
+ * @attr ref android.R.styleable#ProgressBar_progressTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setProgressTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mProgressTint = tint;
+ mProgressTintMode = tintMode;
+ mHasProgressTint = true;
+
+ applyProgressLayerTint(R.id.progress, tint, tintMode, true);
+ }
+
+ /**
+ * Applies a tint to the progress indicator, if one exists, or to the
+ * entire progress drawable otherwise. Does not modify the current tint
+ * mode, which is {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * The progress indicator should be specified as a layer with
+ * id {@link android.R.id#progress} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} will
+ * automatically mutate the drawable and apply the specified tint and
+ * tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_progressTint
+ * @see #setProgressTint(ColorStateList)
+ */
+ public void setProgressTint(@Nullable ColorStateList tint) {
+ setProgressTint(tint, mProgressTintMode);
+ }
+
+ /**
+ * @return the tint applied to the progress drawable
+ * @attr ref android.R.styleable#ProgressBar_progressTint
+ * @see #setProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getProgressTint() {
+ return mProgressTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setProgressTint(ColorStateList)}} to the progress
+ * indicator. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ProgressBar_progressTintMode
+ * @see #setProgressTint(ColorStateList)
+ */
+ public void setProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setProgressTint(mProgressTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the progress drawable
+ * @attr ref android.R.styleable#ProgressBar_progressTintMode
+ * @see #setProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getProgressTintMode() {
+ return mProgressTintMode;
+ }
+
+ /**
+ * Applies a tint to the progress background, if one exists.
+ * <p>
+ * The progress background must be specified as a layer with
+ * id {@link android.R.id#background} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+ * drawable contains a progress background will automatically mutate the
+ * drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setProgressBackgroundTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mProgressBackgroundTint = tint;
+ mProgressBackgroundTintMode = tintMode;
+ mHasProgressBackgroundTint = true;
+
+ applyProgressLayerTint(R.id.background, tint, tintMode, false);
+ }
+
+ /**
+ * Applies a tint to the progress background, if one exists. Does not
+ * modify the current tint mode, which is
+ * {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * The progress background must be specified as a layer with
+ * id {@link android.R.id#background} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+ * drawable contains a progress background will automatically mutate the
+ * drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
+ * @see #setProgressBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setProgressBackgroundTint(@Nullable ColorStateList tint) {
+ setProgressBackgroundTint(tint, mProgressBackgroundTintMode);
+ }
+
+ /**
+ * @return the tint applied to the progress background
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
+ * @see #setProgressBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getProgressBackgroundTint() {
+ return mProgressBackgroundTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setProgressBackgroundTint(ColorStateList)}} to the progress
+ * background. The default mode is {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
+ * @see #setProgressBackgroundTint(ColorStateList)
+ */
+ public void setProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setProgressBackgroundTint(mProgressBackgroundTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the progress
+ * background
+ * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
+ * @see #setProgressBackgroundTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getProgressBackgroundTintMode() {
+ return mProgressBackgroundTintMode;
+ }
+
+ /**
+ * Applies a tint to the secondary progress indicator, if one exists.
+ * <p>
+ * The secondary progress indicator must be specified as a layer with
+ * id {@link android.R.id#secondaryProgress} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+ * drawable contains a secondary progress indicator will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
+ * @see Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+ private void setSecondaryProgressTint(@Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode) {
+ mSecondaryProgressTint = tint;
+ mSecondaryProgressTintMode = tintMode;
+ mHasSecondaryProgressTint = true;
+
+ applyProgressLayerTint(R.id.secondaryProgress, tint, tintMode, false);
+ }
+
+ /**
+ * Applies a tint to the secondary progress indicator, if one exists.
+ * Does not modify the current tint mode, which is
+ * {@link PorterDuff.Mode#SRC_ATOP} by default.
+ * <p>
+ * The secondary progress indicator must be specified as a layer with
+ * id {@link android.R.id#secondaryProgress} in a {@link LayerDrawable}
+ * used as the progress drawable.
+ * <p>
+ * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
+ * drawable contains a secondary progress indicator will automatically
+ * mutate the drawable and apply the specified tint and tint mode using
+ * {@link Drawable#setTint(ColorStateList, android.graphics.PorterDuff.Mode)}.
+ *
+ * @param tint the tint to apply, may be {@code null} to clear tint
+ *
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
+ * @see #setSecondaryProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ public void setSecondaryProgressTint(@Nullable ColorStateList tint) {
+ setSecondaryProgressTint(tint, mSecondaryProgressTintMode);
+ }
+
+ /**
+ * @return the tint applied to the secondary progress drawable
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
+ * @see #setSecondaryProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public ColorStateList getSecondaryProgressTint() {
+ return mSecondaryProgressTint;
+ }
+
+ /**
+ * Specifies the blending mode used to apply the tint specified by
+ * {@link #setSecondaryProgressTint(ColorStateList)}} to the secondary
+ * progress indicator. The default mode is
+ * {@link PorterDuff.Mode#SRC_ATOP}.
+ *
+ * @param tintMode the blending mode used to apply the tint, may be
+ * {@code null} to clear tint
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
+ * @see #setSecondaryProgressTint(ColorStateList)
+ */
+ public void setSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
+ setSecondaryProgressTint(mSecondaryProgressTint, tintMode);
+ }
+
+ /**
+ * @return the blending mode used to apply the tint to the secondary
+ * progress drawable
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
+ * @see #setSecondaryProgressTint(ColorStateList, PorterDuff.Mode)
+ */
+ @Nullable
+ public PorterDuff.Mode getSecondaryProgressTintMode() {
+ return mSecondaryProgressTintMode;
+ }
+
+ private void applyProgressLayerTint(int layerId, @Nullable ColorStateList tint,
+ @Nullable PorterDuff.Mode tintMode, boolean shouldFallback) {
+ final Drawable d = mProgressDrawable;
+ if (d != null) {
+ mProgressDrawable = d.mutate();
+
+ Drawable layer = null;
+ if (d instanceof LayerDrawable) {
+ layer = ((LayerDrawable) d).findDrawableByLayerId(layerId);
+ }
+
+ if (shouldFallback && layer == null) {
+ layer = d;
+ }
+
+ if (layer != null) {
+ layer.setTint(tint, tintMode);
+ }
+ }
+ }
+
+ /**
* Define the tileable drawable used to draw the progress bar in
* progress mode.
* <p>
@@ -670,6 +1133,22 @@
}
}
+ private void setDrawableTint(int id, ColorStateList tint, Mode tintMode, boolean fallback) {
+ Drawable layer = null;
+
+ // We expect a layer drawable, so try to find the target ID.
+ final Drawable d = mCurrentDrawable;
+ if (d instanceof LayerDrawable) {
+ layer = ((LayerDrawable) d).findDrawableByLayerId(id);
+ }
+
+ if (fallback && layer == null) {
+ layer = d;
+ }
+
+ layer.mutate().setTint(tint, tintMode);
+ }
+
private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
boolean callBackToApp) {
float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
@@ -1144,6 +1623,20 @@
}
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ if (mProgressDrawable != null) {
+ mProgressDrawable.setHotspot(x, y);
+ }
+
+ if (mIndeterminateDrawable != null) {
+ mIndeterminateDrawable.setHotspot(x, y);
+ }
+ }
+
static class SavedState extends BaseSavedState {
int progress;
int secondaryProgress;
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index 0c31496..14d782d 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -112,6 +112,16 @@
}
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ if (mOverlay != null) {
+ mOverlay.setHotspot(x, y);
+ }
+ }
+
/** This call has no effect anymore, as there is only one QuickContact mode */
@SuppressWarnings("unused")
public void setMode(int size) {
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index bb74c44..883183e 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -317,13 +317,13 @@
final Resources res = getResources();
mAmPmUnselectedColor = a.getColor(R.styleable.TimePicker_amPmUnselectedBackgroundColor,
- res.getColor(R.color.timepicker_default_ampm_unselected_background_color_quantum));
+ res.getColor(R.color.timepicker_default_ampm_unselected_background_color_material));
mAmPmSelectedColor = a.getColor(R.styleable.TimePicker_amPmSelectedBackgroundColor,
- res.getColor(R.color.timepicker_default_ampm_selected_background_color_quantum));
+ res.getColor(R.color.timepicker_default_ampm_selected_background_color_material));
mAmPmTextColor = a.getColor(R.styleable.TimePicker_amPmTextColor,
- res.getColor(R.color.timepicker_default_text_color_quantum));
+ res.getColor(R.color.timepicker_default_text_color_material));
mTypeface = Typeface.create("sans-serif", Typeface.NORMAL);
@@ -338,7 +338,7 @@
}
final int numbersTextColor = a.getColor(R.styleable.TimePicker_numbersTextColor,
- res.getColor(R.color.timepicker_default_text_color_quantum));
+ res.getColor(R.color.timepicker_default_text_color_material));
mPaint[HOURS] = new Paint();
mPaint[HOURS].setAntiAlias(true);
@@ -358,39 +358,39 @@
mPaintSelector[HOURS][SELECTOR_CIRCLE].setAntiAlias(true);
mColorSelector[HOURS][SELECTOR_CIRCLE] = a.getColor(
R.styleable.TimePicker_numbersSelectorColor,
- R.color.timepicker_default_selector_color_quantum);
+ R.color.timepicker_default_selector_color_material);
mPaintSelector[HOURS][SELECTOR_DOT] = new Paint();
mPaintSelector[HOURS][SELECTOR_DOT].setAntiAlias(true);
mColorSelector[HOURS][SELECTOR_DOT] = a.getColor(
R.styleable.TimePicker_numbersSelectorColor,
- R.color.timepicker_default_selector_color_quantum);
+ R.color.timepicker_default_selector_color_material);
mPaintSelector[HOURS][SELECTOR_LINE] = new Paint();
mPaintSelector[HOURS][SELECTOR_LINE].setAntiAlias(true);
mPaintSelector[HOURS][SELECTOR_LINE].setStrokeWidth(2);
mColorSelector[HOURS][SELECTOR_LINE] = a.getColor(
R.styleable.TimePicker_numbersSelectorColor,
- R.color.timepicker_default_selector_color_quantum);
+ R.color.timepicker_default_selector_color_material);
mPaintSelector[MINUTES][SELECTOR_CIRCLE] = new Paint();
mPaintSelector[MINUTES][SELECTOR_CIRCLE].setAntiAlias(true);
mColorSelector[MINUTES][SELECTOR_CIRCLE] = a.getColor(
R.styleable.TimePicker_numbersSelectorColor,
- R.color.timepicker_default_selector_color_quantum);
+ R.color.timepicker_default_selector_color_material);
mPaintSelector[MINUTES][SELECTOR_DOT] = new Paint();
mPaintSelector[MINUTES][SELECTOR_DOT].setAntiAlias(true);
mColorSelector[MINUTES][SELECTOR_DOT] = a.getColor(
R.styleable.TimePicker_numbersSelectorColor,
- R.color.timepicker_default_selector_color_quantum);
+ R.color.timepicker_default_selector_color_material);
mPaintSelector[MINUTES][SELECTOR_LINE] = new Paint();
mPaintSelector[MINUTES][SELECTOR_LINE].setAntiAlias(true);
mPaintSelector[MINUTES][SELECTOR_LINE].setStrokeWidth(2);
mColorSelector[MINUTES][SELECTOR_LINE] = a.getColor(
R.styleable.TimePicker_numbersSelectorColor,
- R.color.timepicker_default_selector_color_quantum);
+ R.color.timepicker_default_selector_color_material);
mPaintAmPmText.setColor(mAmPmTextColor);
mPaintAmPmText.setTypeface(mTypeface);
@@ -403,11 +403,11 @@
mPaintAmPmCircle[PM].setAntiAlias(true);
mPaintBackground.setColor(a.getColor(R.styleable.TimePicker_numbersBackgroundColor,
- res.getColor(R.color.timepicker_default_numbers_background_color_quantum)));
+ res.getColor(R.color.timepicker_default_numbers_background_color_material)));
mPaintBackground.setAntiAlias(true);
mPaintDisabled.setColor(a.getColor(R.styleable.TimePicker_disabledColor,
- res.getColor(R.color.timepicker_default_disabled_color_quantum)));
+ res.getColor(R.color.timepicker_default_disabled_color_material)));
mPaintDisabled.setAntiAlias(true);
if (DEBUG) {
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index c5c6e64..03193a2 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -962,6 +962,20 @@
invalidate();
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ if (mThumbDrawable != null) {
+ mThumbDrawable.setHotspot(x, y);
+ }
+
+ if (mTrackDrawable != null) {
+ mTrackDrawable.setHotspot(x, y);
+ }
+ }
+
@Override
public void invalidateDrawable(Drawable drawable) {
super.invalidateDrawable(drawable);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 43c8dde..0f51e8b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2551,7 +2551,7 @@
r = c.getResources();
setRawTextSize(TypedValue.applyDimension(
- unit, size, r.getDisplayMetrics()));
+ unit, size, r.getDisplayMetrics()));
}
private void setRawTextSize(float size) {
@@ -2727,7 +2727,6 @@
/**
* Sets whether the soft input method will be made visible when this
* TextView gets focused. The default is true.
- * @hide
*/
@android.view.RemotableViewMethod
public final void setShowSoftInputOnFocus(boolean show) {
@@ -2738,7 +2737,6 @@
/**
* Returns whether the soft input method will be made visible when this
* TextView gets focused. The default is true.
- * @hide
*/
public final boolean getShowSoftInputOnFocus() {
// When there is no Editor, return default true value
@@ -3505,6 +3503,34 @@
}
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ final Drawables dr = mDrawables;
+ if (dr != null) {
+ if (dr.mDrawableTop != null) {
+ dr.mDrawableTop.setHotspot(x, y);
+ }
+ if (dr.mDrawableBottom != null) {
+ dr.mDrawableBottom.setHotspot(x, y);
+ }
+ if (dr.mDrawableLeft != null) {
+ dr.mDrawableLeft.setHotspot(x, y);
+ }
+ if (dr.mDrawableRight != null) {
+ dr.mDrawableRight.setHotspot(x, y);
+ }
+ if (dr.mDrawableStart != null) {
+ dr.mDrawableStart.setHotspot(x, y);
+ }
+ if (dr.mDrawableEnd != null) {
+ dr.mDrawableEnd.setHotspot(x, y);
+ }
+ }
+ }
+
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
@@ -5842,7 +5868,6 @@
int end = text.partialEndOffset;
if (end > N) end = N;
removeParcelableSpans(content, start, end);
- // If start > end, content.replace will swap them before using them.
content.replace(start, end, text.text);
}
}
@@ -9035,11 +9060,11 @@
}
public void drawTextRun(Canvas c, int start, int end,
- int contextStart, int contextEnd, float x, float y, int flags, Paint p) {
+ int contextStart, int contextEnd, float x, float y, boolean isRtl, Paint p) {
int count = end - start;
int contextCount = contextEnd - contextStart;
c.drawTextRun(mChars, start + mStart, count, contextStart + mStart,
- contextCount, x, y, flags, p);
+ contextCount, x, y, isRtl, p);
}
public float measureText(int start, int end, Paint p) {
@@ -9051,20 +9076,20 @@
}
public float getTextRunAdvances(int start, int end, int contextStart,
- int contextEnd, int flags, float[] advances, int advancesIndex,
+ int contextEnd, boolean isRtl, float[] advances, int advancesIndex,
Paint p) {
int count = end - start;
int contextCount = contextEnd - contextStart;
return p.getTextRunAdvances(mChars, start + mStart, count,
- contextStart + mStart, contextCount, flags, advances,
+ contextStart + mStart, contextCount, isRtl, advances,
advancesIndex);
}
- public int getTextRunCursor(int contextStart, int contextEnd, int flags,
+ public int getTextRunCursor(int contextStart, int contextEnd, int dir,
int offset, int cursorOpt, Paint p) {
int contextCount = contextEnd - contextStart;
return p.getTextRunCursor(mChars, contextStart + mStart,
- contextCount, flags, offset + mStart, cursorOpt);
+ contextCount, dir, offset + mStart, cursorOpt);
}
}
diff --git a/core/java/android/widget/TimePickerDelegate.java b/core/java/android/widget/TimePickerDelegate.java
index ba93ee5..bf3971c 100644
--- a/core/java/android/widget/TimePickerDelegate.java
+++ b/core/java/android/widget/TimePickerDelegate.java
@@ -140,12 +140,12 @@
mSelectMinutes = res.getString(R.string.select_minutes);
mHeaderSelectedColor = a.getColor(R.styleable.TimePicker_headerSelectedTextColor,
- R.color.timepicker_default_selector_color_quantum);
+ R.color.timepicker_default_selector_color_material);
- mHeaderUnSelectedColor = getUnselectedColor(R.color.timepicker_default_text_color_quantum);
+ mHeaderUnSelectedColor = getUnselectedColor(R.color.timepicker_default_text_color_material);
if (mHeaderUnSelectedColor == -1) {
mHeaderUnSelectedColor = a.getColor(R.styleable.TimePicker_headerUnselectedTextColor,
- R.color.timepicker_default_text_color_quantum);
+ R.color.timepicker_default_text_color_material);
}
final int headerBackgroundColor = a.getColor(
@@ -295,7 +295,7 @@
TypedArray a = mContext.obtainStyledAttributes(TEXT_APPEARANCE_TIME_LABEL_ATTR);
final int textAppearanceResId = a.getResourceId(0, 0);
tempView.setTextAppearance(mContext, (textAppearanceResId != 0) ?
- textAppearanceResId : R.style.TextAppearance_Quantum_TimePicker_TimeLabel);
+ textAppearanceResId : R.style.TextAppearance_Material_TimePicker_TimeLabel);
a.recycle();
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index cbd9a6a..4f1cd68 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -146,6 +146,8 @@
private ActionMenuPresenter mOuterActionMenuPresenter;
private ExpandedActionViewMenuPresenter mExpandedMenuPresenter;
+ private boolean mCollapsible;
+
public Toolbar(Context context) {
this(context, null);
}
@@ -969,6 +971,23 @@
return child.getMeasuredWidth() + hMargins;
}
+ /**
+ * Returns true if the Toolbar is collapsible and has no child views with a measured size > 0.
+ */
+ private boolean shouldCollapse() {
+ if (!mCollapsible) return false;
+
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ if (shouldLayout(child) && child.getMeasuredWidth() > 0 &&
+ child.getMeasuredHeight() > 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = 0;
@@ -1093,7 +1112,8 @@
final int measuredHeight = resolveSizeAndState(
Math.max(height, getSuggestedMinimumHeight()),
heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT);
- setMeasuredDimension(measuredWidth, measuredHeight);
+
+ setMeasuredDimension(measuredWidth, shouldCollapse() ? 0 : measuredHeight);
}
@Override
@@ -1490,6 +1510,16 @@
}
/**
+ * Force the toolbar to collapse to zero-height during measurement if
+ * it could be considered "empty" (no visible elements with nonzero measured size)
+ * @hide
+ */
+ public void setCollapsible(boolean collapsible) {
+ mCollapsible = collapsible;
+ requestLayout();
+ }
+
+ /**
* Interface responsible for receiving menu item click events if the items themselves
* do not have individual item click listeners.
*/
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 2b62552..8ee0a1b 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -22,6 +22,7 @@
import android.content.res.Resources;
import android.graphics.Canvas;
import android.media.AudioManager;
+import android.media.ClosedCaptionRenderer;
import android.media.MediaFormat;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
@@ -316,6 +317,7 @@
context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer);
controller.registerRenderer(new WebVttRenderer(context));
controller.registerRenderer(new TtmlRenderer(context));
+ controller.registerRenderer(new ClosedCaptionRenderer(context));
mMediaPlayer.setSubtitleAnchor(controller, this);
if (mAudioSession != 0) {
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index d10451b..643225d 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -16,6 +16,7 @@
package com.android.internal.backup;
+import android.app.backup.RestoreDescription;
import android.app.backup.RestoreSet;
import android.content.Intent;
import android.content.pm.PackageInfo;
@@ -168,12 +169,25 @@
int startRestore(long token, in PackageInfo[] packages);
/**
- * Get the package name of the next application with data in the backup store.
- * @return The name of one of the packages supplied to {@link #startRestore},
- * or "" (the empty string) if no more backup data is available,
- * or null if an error occurred (the restore should be aborted and rescheduled).
+ * Get the package name of the next application with data in the backup store, plus
+ * a description of the structure of the restored archive: either TYPE_KEY_VALUE for
+ * an original-API key/value dataset, or TYPE_FULL_STREAM for a tarball-type archive stream.
+ *
+ * <p>If the package name in the returned RestoreDescription object is the singleton
+ * {@link RestoreDescription#NO_MORE_PACKAGES}, it indicates that no further data is available
+ * in the current restore session: all packages described in startRestore() have been
+ * processed.
+ *
+ * <p>If this method returns {@code null}, it means that a transport-level error has
+ * occurred and the entire restore operation should be abandoned.
+ *
+ * @return A RestoreDescription object containing the name of one of the packages
+ * supplied to {@link #startRestore} plus an indicator of the data type of that
+ * restore data; or {@link RestoreDescription#NO_MORE_PACKAGES} to indicate that
+ * no more packages can be restored in this session; or {@code null} to indicate
+ * a transport-level error.
*/
- String nextRestorePackage();
+ RestoreDescription nextRestorePackage();
/**
* Get the data for the application returned by {@link #nextRestorePackage}.
@@ -187,4 +201,59 @@
* freeing any resources and connections used during the restore process.
*/
void finishRestore();
+
+ // full backup stuff
+
+ long requestFullBackupTime();
+ int performFullBackup(in PackageInfo targetPackage, in ParcelFileDescriptor socket);
+ int sendBackupData(int numBytes);
+
+ // full restore stuff
+
+ /**
+ * Ask the transport to provide data for the "current" package being restored. This
+ * is the package that was just reported by {@link #nextRestorePackage()} as having
+ * {@link RestoreDescription#TYPE_FULL_STREAM} data.
+ *
+ * The transport writes some data to the socket supplied to this call, and returns
+ * the number of bytes written. The system will then read that many bytes and
+ * stream them to the application's agent for restore, then will call this method again
+ * to receive the next chunk of the archive. This sequence will be repeated until the
+ * transport returns zero indicating that all of the package's data has been delivered
+ * (or returns a negative value indicating some sort of hard error condition at the
+ * transport level).
+ *
+ * <p>After this method returns zero, the system will then call
+ * {@link #getNextFullRestorePackage()} to begin the restore process for the next
+ * application, and the sequence begins again.
+ *
+ * <p>The transport should always close this socket when returning from this method.
+ * Do not cache this socket across multiple calls or you may leak file descriptors.
+ *
+ * @param socket The file descriptor that the transport will use for delivering the
+ * streamed archive. The transport must close this socket in all cases when returning
+ * from this method.
+ * @return 0 when no more data for the current package is available. A positive value
+ * indicates the presence of that many bytes to be delivered to the app. Any negative
+ * return value is treated as equivalent to {@link BackupTransport#TRANSPORT_ERROR},
+ * indicating a fatal error condition that precludes further restore operations
+ * on the current dataset.
+ */
+ int getNextFullRestoreDataChunk(in ParcelFileDescriptor socket);
+
+ /**
+ * If the OS encounters an error while processing {@link RestoreDescription#TYPE_FULL_STREAM}
+ * data for restore, it will invoke this method to tell the transport that it should
+ * abandon the data download for the current package. The OS will then either call
+ * {@link #nextRestorePackage()} again to move on to restoring the next package in the
+ * set being iterated over, or will call {@link #finishRestore()} to shut down the restore
+ * operation.
+ *
+ * @return {@link #TRANSPORT_OK} if the transport was successful in shutting down the
+ * current stream cleanly, or {@link #TRANSPORT_ERROR} to indicate a serious
+ * transport-level failure. If the transport reports an error here, the entire restore
+ * operation will immediately be finished with no further attempts to restore app data.
+ */
+ int abortFullRestore();
+
}
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 7292116..ff0ee65 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -19,6 +19,7 @@
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupTransport;
+import android.app.backup.RestoreDescription;
import android.app.backup.RestoreSet;
import android.content.ComponentName;
import android.content.Context;
@@ -34,12 +35,17 @@
import com.android.org.bouncycastle.util.encoders.Base64;
+import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
import static android.system.OsConstants.*;
@@ -58,22 +64,41 @@
private static final String TRANSPORT_DESTINATION_STRING
= "Backing up to debug-only private cache";
+ private static final String INCREMENTAL_DIR = "_delta";
+ private static final String FULL_DATA_DIR = "_full";
+
// The currently-active restore set always has the same (nonzero!) token
private static final long CURRENT_SET_TOKEN = 1;
private Context mContext;
private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup");
private File mCurrentSetDir = new File(mDataDir, Long.toString(CURRENT_SET_TOKEN));
+ private File mCurrentSetIncrementalDir = new File(mCurrentSetDir, INCREMENTAL_DIR);
+ private File mCurrentSetFullDir = new File(mCurrentSetDir, FULL_DATA_DIR);
private PackageInfo[] mRestorePackages = null;
private int mRestorePackage = -1; // Index into mRestorePackages
- private File mRestoreDataDir;
+ private int mRestoreType;
+ private File mRestoreSetDir;
+ private File mRestoreSetIncrementalDir;
+ private File mRestoreSetFullDir;
private long mRestoreToken;
+ // Additional bookkeeping for full backup
+ private String mFullTargetPackage;
+ private ParcelFileDescriptor mSocket;
+ private FileInputStream mSocketInputStream;
+ private BufferedOutputStream mFullBackupOutputStream;
+ private byte[] mFullBackupBuffer;
+
+ private File mFullRestoreSetDir;
+ private HashSet<String> mFullRestorePackages;
public LocalTransport(Context context) {
mContext = context;
mCurrentSetDir.mkdirs();
+ mCurrentSetFullDir.mkdir();
+ mCurrentSetIncrementalDir.mkdir();
if (!SELinux.restorecon(mCurrentSetDir)) {
Log.e(TAG, "SELinux restorecon failed for " + mCurrentSetDir);
}
@@ -119,7 +144,7 @@
}
}
- File packageDir = new File(mCurrentSetDir, packageInfo.packageName);
+ File packageDir = new File(mCurrentSetIncrementalDir, packageInfo.packageName);
packageDir.mkdirs();
// Each 'record' in the restore set is kept in its own file, named by
@@ -200,7 +225,7 @@
public int clearBackupData(PackageInfo packageInfo) {
if (DEBUG) Log.v(TAG, "clearBackupData() pkg=" + packageInfo.packageName);
- File packageDir = new File(mCurrentSetDir, packageInfo.packageName);
+ File packageDir = new File(mCurrentSetIncrementalDir, packageInfo.packageName);
final File[] fileset = packageDir.listFiles();
if (fileset != null) {
for (File f : fileset) {
@@ -208,27 +233,122 @@
}
packageDir.delete();
}
+
+ packageDir = new File(mCurrentSetFullDir, packageInfo.packageName);
+ final File[] tarballs = packageDir.listFiles();
+ if (tarballs != null) {
+ for (File f : tarballs) {
+ f.delete();
+ }
+ packageDir.delete();
+ }
+
return BackupTransport.TRANSPORT_OK;
}
public int finishBackup() {
if (DEBUG) Log.v(TAG, "finishBackup()");
+ if (mSocket != null) {
+ if (DEBUG) {
+ Log.v(TAG, "Concluding full backup of " + mFullTargetPackage);
+ }
+ try {
+ mFullBackupOutputStream.flush();
+ mFullBackupOutputStream.close();
+ mSocketInputStream = null;
+ mFullTargetPackage = null;
+ mSocket.close();
+ } catch (IOException e) {
+ return BackupTransport.TRANSPORT_ERROR;
+ } finally {
+ mSocket = null;
+ }
+ }
return BackupTransport.TRANSPORT_OK;
}
+ // ------------------------------------------------------------------------------------
+ // Full backup handling
+ public long requestFullBackupTime() {
+ return 0;
+ }
+
+ public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket) {
+ if (mSocket != null) {
+ Log.e(TAG, "Attempt to initiate full backup while one is in progress");
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ if (DEBUG) {
+ Log.i(TAG, "performFullBackup : " + targetPackage);
+ }
+
+ // We know a priori that we run in the system process, so we need to make
+ // sure to dup() our own copy of the socket fd. Transports which run in
+ // their own processes must not do this.
+ try {
+ mSocket = ParcelFileDescriptor.dup(socket.getFileDescriptor());
+ mSocketInputStream = new FileInputStream(mSocket.getFileDescriptor());
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to process socket for full backup");
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ mFullTargetPackage = targetPackage.packageName;
+ FileOutputStream tarstream;
+ try {
+ File tarball = new File(mCurrentSetFullDir, mFullTargetPackage);
+ tarstream = new FileOutputStream(tarball);
+ } catch (FileNotFoundException e) {
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+ mFullBackupOutputStream = new BufferedOutputStream(tarstream);
+ mFullBackupBuffer = new byte[4096];
+
+ return BackupTransport.TRANSPORT_OK;
+ }
+
+ public int sendBackupData(int numBytes) {
+ if (mFullBackupBuffer == null) {
+ Log.w(TAG, "Attempted sendBackupData before performFullBackup");
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ if (numBytes > mFullBackupBuffer.length) {
+ mFullBackupBuffer = new byte[numBytes];
+ }
+ while (numBytes > 0) {
+ try {
+ int nRead = mSocketInputStream.read(mFullBackupBuffer, 0, numBytes);
+ if (nRead < 0) {
+ // Something went wrong if we expect data but saw EOD
+ Log.w(TAG, "Unexpected EOD; failing backup");
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+ mFullBackupOutputStream.write(mFullBackupBuffer, 0, nRead);
+ numBytes -= nRead;
+ } catch (IOException e) {
+ Log.e(TAG, "Error handling backup data for " + mFullTargetPackage);
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+ }
+ return BackupTransport.TRANSPORT_OK;
+ }
+
+ // ------------------------------------------------------------------------------------
// Restore handling
static final long[] POSSIBLE_SETS = { 2, 3, 4, 5, 6, 7, 8, 9 };
public RestoreSet[] getAvailableRestoreSets() {
long[] existing = new long[POSSIBLE_SETS.length + 1];
int num = 0;
- // see which possible non-current sets exist, then put the current set at the end
+ // see which possible non-current sets exist...
for (long token : POSSIBLE_SETS) {
if ((new File(mDataDir, Long.toString(token))).exists()) {
existing[num++] = token;
}
}
- // and always the currently-active set last
+ // ...and always the currently-active set last
existing[num++] = CURRENT_SET_TOKEN;
RestoreSet[] available = new RestoreSet[num];
@@ -248,30 +368,55 @@
mRestorePackages = packages;
mRestorePackage = -1;
mRestoreToken = token;
- mRestoreDataDir = new File(mDataDir, Long.toString(token));
+ mRestoreSetDir = new File(mDataDir, Long.toString(token));
+ mRestoreSetIncrementalDir = new File(mRestoreSetDir, INCREMENTAL_DIR);
+ mRestoreSetFullDir = new File(mRestoreSetDir, FULL_DATA_DIR);
return BackupTransport.TRANSPORT_OK;
}
- public String nextRestorePackage() {
+ @Override
+ public RestoreDescription nextRestorePackage() {
if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
+
+ boolean found = false;
while (++mRestorePackage < mRestorePackages.length) {
String name = mRestorePackages[mRestorePackage].packageName;
+
+ // If we have key/value data for this package, deliver that
// skip packages where we have a data dir but no actual contents
- String[] contents = (new File(mRestoreDataDir, name)).list();
+ String[] contents = (new File(mRestoreSetIncrementalDir, name)).list();
if (contents != null && contents.length > 0) {
- if (DEBUG) Log.v(TAG, " nextRestorePackage() = " + name);
- return name;
+ if (DEBUG) Log.v(TAG, " nextRestorePackage(TYPE_KEY_VALUE) = " + name);
+ mRestoreType = RestoreDescription.TYPE_KEY_VALUE;
+ found = true;
+ }
+
+ if (!found) {
+ // No key/value data; check for [non-empty] full data
+ File maybeFullData = new File(mRestoreSetFullDir, name);
+ if (maybeFullData.length() > 0) {
+ if (DEBUG) Log.v(TAG, " nextRestorePackage(TYPE_FULL_STREAM) = " + name);
+ mRestoreType = RestoreDescription.TYPE_FULL_STREAM;
+ found = true;
+ }
+ }
+
+ if (found) {
+ return new RestoreDescription(name, mRestoreType);
}
}
if (DEBUG) Log.v(TAG, " no more packages to restore");
- return "";
+ return RestoreDescription.NO_MORE_PACKAGES;
}
public int getRestoreData(ParcelFileDescriptor outFd) {
if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called");
- File packageDir = new File(mRestoreDataDir, mRestorePackages[mRestorePackage].packageName);
+ if (mRestoreType != RestoreDescription.TYPE_KEY_VALUE) {
+ throw new IllegalStateException("getRestoreData(fd) for non-key/value dataset");
+ }
+ File packageDir = new File(mRestoreSetDir, mRestorePackages[mRestorePackage].packageName);
// The restore set is the concatenation of the individual record blobs,
// each of which is a file in the package's directory. We return the
@@ -345,4 +490,60 @@
public void finishRestore() {
if (DEBUG) Log.v(TAG, "finishRestore()");
}
+
+ // ------------------------------------------------------------------------------------
+ // Full restore handling
+
+ public int prepareFullRestore(long token, String[] targetPackages) {
+ mRestoreSetDir = new File(mDataDir, Long.toString(token));
+ mFullRestoreSetDir = new File(mRestoreSetDir, FULL_DATA_DIR);
+ mFullRestorePackages = new HashSet<String>();
+ if (mFullRestoreSetDir.exists()) {
+ List<String> pkgs = Arrays.asList(mFullRestoreSetDir.list());
+ HashSet<String> available = new HashSet<String>(pkgs);
+
+ for (int i = 0; i < targetPackages.length; i++) {
+ if (available.contains(targetPackages[i])) {
+ mFullRestorePackages.add(targetPackages[i]);
+ }
+ }
+ }
+ return BackupTransport.TRANSPORT_OK;
+ }
+
+ /**
+ * Ask the transport what package's full data will be restored next. When all apps'
+ * data has been delivered, the transport should return {@code null} here.
+ * @return The package name of the next application whose data will be restored, or
+ * {@code null} if all available package has been delivered.
+ */
+ public String getNextFullRestorePackage() {
+ return null;
+ }
+
+ /**
+ * Ask the transport to provide data for the "current" package being restored. The
+ * transport then writes some data to the socket supplied to this call, and returns
+ * the number of bytes written. The system will then read that many bytes and
+ * stream them to the application's agent for restore, then will call this method again
+ * to receive the next chunk of the archive. This sequence will be repeated until the
+ * transport returns zero indicating that all of the package's data has been delivered
+ * (or returns a negative value indicating some sort of hard error condition at the
+ * transport level).
+ *
+ * <p>After this method returns zero, the system will then call
+ * {@link #getNextFullRestorePackage()} to begin the restore process for the next
+ * application, and the sequence begins again.
+ *
+ * @param socket The file descriptor that the transport will use for delivering the
+ * streamed archive.
+ * @return 0 when no more data for the current package is available. A positive value
+ * indicates the presence of that much data to be delivered to the app. A negative
+ * return value is treated as equivalent to {@link BackupTransport#TRANSPORT_ERROR},
+ * indicating a fatal error condition that precludes further restore operations
+ * on the current dataset.
+ */
+ public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) {
+ return 0;
+ }
}
diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java
index 7edf4cc..c977997 100644
--- a/core/java/com/android/internal/os/SomeArgs.java
+++ b/core/java/com/android/internal/os/SomeArgs.java
@@ -45,6 +45,7 @@
public Object arg3;
public Object arg4;
public Object arg5;
+ public Object arg6;
public int argi1;
public int argi2;
public int argi3;
@@ -95,6 +96,7 @@
arg3 = null;
arg4 = null;
arg5 = null;
+ arg6 = null;
argi1 = 0;
argi2 = 0;
argi3 = 0;
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index f38cbde..665055c 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -35,7 +35,7 @@
import java.util.WeakHashMap;
/**
- * Helper class to process legacy (Holo) notifications to make them look like quantum notifications.
+ * Helper class to process legacy (Holo) notifications to make them look like material notifications.
*
* @hide
*/
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index 9e8d12b..b100d27 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -28,4 +28,5 @@
void onUnbindMethod(int sequence);
void setActive(boolean active);
void setCursorAnchorMonitorMode(int monitorMode);
+ void setUserActionNotificationSequenceNumber(int sequenceNumber);
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 4590520..b84c359 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -77,6 +77,6 @@
boolean setInputMethodEnabled(String id, boolean enabled);
void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
int getInputMethodWindowVisibleHeight();
- oneway void notifyUserAction();
+ oneway void notifyUserAction(int sequenceNumber);
void setCursorAnchorMonitorMode(in IBinder token, int monitorMode);
}
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
index 14afe21..3a3e56d 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -47,13 +47,19 @@
* Sequence number of this binding.
*/
public final int sequence;
-
+
+ /**
+ * Sequence number of user action notification.
+ */
+ public final int userActionNotificationSequenceNumber;
+
public InputBindResult(IInputMethodSession _method, InputChannel _channel,
- String _id, int _sequence) {
+ String _id, int _sequence, int _userActionNotificationSequenceNumber) {
method = _method;
channel = _channel;
id = _id;
sequence = _sequence;
+ userActionNotificationSequenceNumber = _userActionNotificationSequenceNumber;
}
InputBindResult(Parcel source) {
@@ -65,12 +71,15 @@
}
id = source.readString();
sequence = source.readInt();
+ userActionNotificationSequenceNumber = source.readInt();
}
@Override
public String toString() {
return "InputBindResult{" + method + " " + id
- + " #" + sequence + "}";
+ + " sequence:" + sequence
+ + " userActionNotificationSequenceNumber:" + userActionNotificationSequenceNumber
+ + "}";
}
/**
@@ -90,6 +99,7 @@
}
dest.writeString(id);
dest.writeInt(sequence);
+ dest.writeInt(userActionNotificationSequenceNumber);
}
/**
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 8a9cb22..ea36e37 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -20,6 +20,7 @@
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
@@ -246,6 +247,13 @@
}
@Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ init(getContext());
+ requestApplyInsets();
+ }
+
+ @Override
public void onWindowSystemUiVisibilityChanged(int visible) {
super.onWindowSystemUiVisibilityChanged(visible);
pullChildren();
@@ -329,7 +337,7 @@
// insets in all cases, we need to know the measured size of the various action
// bar elements. onApplyWindowInsets() happens before the measure pass, so we can't
// do that here. Instead we will take this up in onMeasure().
- return WindowInsets.EMPTY;
+ return WindowInsets.CONSUMED;
}
@Override
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 7fe03f5..60e649b 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -291,14 +291,14 @@
mPathPaint.setStrokeCap(Paint.Cap.ROUND);
// lot's of bitmaps!
- // TODO: those bitmaps are hardcoded to the Quantum Theme which should not be the case!
- mBitmapBtnDefault = getBitmapFor(R.drawable.btn_code_lock_default_qntm_alpha);
- mBitmapBtnTouched = getBitmapFor(R.drawable.btn_code_lock_touched_qntm_alpha);
+ // TODO: those bitmaps are hardcoded to the Material Theme which should not be the case!
+ mBitmapBtnDefault = getBitmapFor(R.drawable.btn_code_lock_default_mtrl_alpha);
+ mBitmapBtnTouched = getBitmapFor(R.drawable.btn_code_lock_touched_mtrl_alpha);
mBitmapCircleDefault = getBitmapFor(
- R.drawable.indicator_code_lock_point_area_default_qntm_alpha);
- mBitmapCircleAlpha = getBitmapFor(R.drawable.indicator_code_lock_point_area_qntm_alpha);
+ R.drawable.indicator_code_lock_point_area_default_mtrl_alpha);
+ mBitmapCircleAlpha = getBitmapFor(R.drawable.indicator_code_lock_point_area_mtrl_alpha);
mBitmapArrowAlphaUp = getBitmapFor(
- R.drawable.indicator_code_lock_drag_direction_up_qntm_alpha);
+ R.drawable.indicator_code_lock_drag_direction_up_mtrl_alpha);
// bitmaps have the size of the largest bitmap in this group
final Bitmap bitmaps[] = { mBitmapBtnDefault, mBitmapBtnTouched, mBitmapCircleDefault,
diff --git a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
index b298d85..7fb2efd 100644
--- a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
+++ b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
@@ -424,7 +424,7 @@
@Override
public void setCollapsible(boolean collapsible) {
- // Ignore
+ mToolbar.setCollapsible(collapsible);
}
@Override
@@ -480,7 +480,7 @@
private void ensureSpinner() {
if (mSpinner == null) {
- mSpinner = new Spinner(getContext());
+ mSpinner = new Spinner(getContext(), null, R.attr.actionDropDownStyle);
Toolbar.LayoutParams lp = new Toolbar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL);
mSpinner.setLayoutParams(lp);
@@ -569,7 +569,7 @@
@Override
public void setNavigationIcon(int resId) {
- setNavigationIcon(mToolbar.getContext().getDrawable(resId));
+ setNavigationIcon(resId != 0 ? mToolbar.getContext().getDrawable(resId) : null);
}
@Override
diff --git a/core/java/com/android/server/SystemService.java b/core/java/com/android/server/SystemService.java
index bf36bb1..43a05d0 100644
--- a/core/java/com/android/server/SystemService.java
+++ b/core/java/com/android/server/SystemService.java
@@ -193,58 +193,4 @@
private SystemServiceManager getManager() {
return LocalServices.getService(SystemServiceManager.class);
}
-
-// /**
-// * Called when a new user has been created. If your service deals with multiple users, this
-// * method should be overridden.
-// *
-// * @param userHandle The user that was created.
-// */
-// public void onUserCreated(int userHandle) {
-// }
-//
-// /**
-// * Called when an existing user has started a new session. If your service deals with multiple
-// * users, this method should be overridden.
-// *
-// * @param userHandle The user who started a new session.
-// */
-// public void onUserStarted(int userHandle) {
-// }
-//
-// /**
-// * Called when a background user session has entered the foreground. If your service deals with
-// * multiple users, this method should be overridden.
-// *
-// * @param userHandle The user who's session entered the foreground.
-// */
-// public void onUserForeground(int userHandle) {
-// }
-//
-// /**
-// * Called when a foreground user session has entered the background. If your service deals with
-// * multiple users, this method should be overridden;
-// *
-// * @param userHandle The user who's session entered the background.
-// */
-// public void onUserBackground(int userHandle) {
-// }
-//
-// /**
-// * Called when a user's active session has stopped. If your service deals with multiple users,
-// * this method should be overridden.
-// *
-// * @param userHandle The user who's session has stopped.
-// */
-// public void onUserStopped(int userHandle) {
-// }
-//
-// /**
-// * Called when a user has been removed from the system. If your service deals with multiple
-// * users, this method should be overridden.
-// *
-// * @param userHandle The user who has been removed.
-// */
-// public void onUserRemoved(int userHandle) {
-// }
}
diff --git a/core/java/com/android/server/net/BaseNetworkObserver.java b/core/java/com/android/server/net/BaseNetworkObserver.java
index 430dd63..3d9fb5c 100644
--- a/core/java/com/android/server/net/BaseNetworkObserver.java
+++ b/core/java/com/android/server/net/BaseNetworkObserver.java
@@ -18,6 +18,7 @@
import android.net.INetworkManagementEventObserver;
import android.net.LinkAddress;
+import android.net.RouteInfo;
/**
* Base {@link INetworkManagementEventObserver} that provides no-op
@@ -70,4 +71,14 @@
public void interfaceDnsServerInfo(String iface, long lifetime, String[] servers) {
// default no-op
}
+
+ @Override
+ public void routeUpdated(RouteInfo route) {
+ // default no-op
+ }
+
+ @Override
+ public void routeRemoved(RouteInfo route) {
+ // default no-op
+ }
}
diff --git a/core/java/com/android/server/net/NetlinkTracker.java b/core/java/com/android/server/net/NetlinkTracker.java
new file mode 100644
index 0000000..7dd8dd8
--- /dev/null
+++ b/core/java/com/android/server/net/NetlinkTracker.java
@@ -0,0 +1,161 @@
+/*
+ * 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.server.net;
+
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.RouteInfo;
+import android.util.Log;
+
+/**
+ * Keeps track of link configuration received from Netlink.
+ *
+ * Instances of this class are expected to be owned by subsystems such as Wi-Fi
+ * or Ethernet that manage one or more network interfaces. Each interface to be
+ * tracked needs its own {@code NetlinkTracker}.
+ *
+ * An instance of this class is constructed by passing in an interface name and
+ * a callback. The owner is then responsible for registering the tracker with
+ * NetworkManagementService. When the class receives update notifications from
+ * the NetworkManagementService notification threads, it applies the update to
+ * its local LinkProperties, and if something has changed, notifies its owner of
+ * the update via the callback.
+ *
+ * The owner can then call {@code getLinkProperties()} in order to find out
+ * what changed. If in the meantime the LinkProperties stored here have changed,
+ * this class will return the current LinkProperties. Because each change
+ * triggers an update callback after the change is made, the owner may get more
+ * callbacks than strictly necessary (some of which may be no-ops), but will not
+ * be out of sync once all callbacks have been processed.
+ *
+ * Threading model:
+ *
+ * - The owner of this class is expected to create it, register it, and call
+ * getLinkProperties or clearLinkProperties on its thread.
+ * - Most of the methods in the class are inherited from BaseNetworkObserver
+ * and are called by NetworkManagementService notification threads.
+ * - All accesses to mLinkProperties must be synchronized(this). All the other
+ * member variables are immutable once the object is constructed.
+ *
+ * This class currently tracks IPv4 and IPv6 addresses. In the future it will
+ * track routes and DNS servers.
+ *
+ * @hide
+ */
+public class NetlinkTracker extends BaseNetworkObserver {
+
+ private final String TAG;
+
+ public interface Callback {
+ public void update();
+ }
+
+ private final String mInterfaceName;
+ private final Callback mCallback;
+ private final LinkProperties mLinkProperties;
+
+ private static final boolean DBG = true;
+
+ public NetlinkTracker(String iface, Callback callback) {
+ TAG = "NetlinkTracker/" + iface;
+ mInterfaceName = iface;
+ mCallback = callback;
+ mLinkProperties = new LinkProperties();
+ mLinkProperties.setInterfaceName(mInterfaceName);
+ }
+
+ private void maybeLog(String operation, String iface, LinkAddress address) {
+ if (DBG) {
+ Log.d(TAG, operation + ": " + address + " on " + iface +
+ " flags " + address.getFlags() + " scope " + address.getScope());
+ }
+ }
+
+ private void maybeLog(String operation, Object o) {
+ if (DBG) {
+ Log.d(TAG, operation + ": " + o.toString());
+ }
+ }
+
+ @Override
+ public void addressUpdated(String iface, LinkAddress address) {
+ if (mInterfaceName.equals(iface)) {
+ maybeLog("addressUpdated", iface, address);
+ boolean changed;
+ synchronized (this) {
+ changed = mLinkProperties.addLinkAddress(address);
+ }
+ if (changed) {
+ mCallback.update();
+ }
+ }
+ }
+
+ @Override
+ public void addressRemoved(String iface, LinkAddress address) {
+ if (mInterfaceName.equals(iface)) {
+ maybeLog("addressRemoved", iface, address);
+ boolean changed;
+ synchronized (this) {
+ changed = mLinkProperties.removeLinkAddress(address);
+ }
+ if (changed) {
+ mCallback.update();
+ }
+ }
+ }
+
+ @Override
+ public void routeUpdated(RouteInfo route) {
+ if (mInterfaceName.equals(route.getInterface())) {
+ maybeLog("routeUpdated", route);
+ boolean changed;
+ synchronized (this) {
+ changed = mLinkProperties.addRoute(route);
+ }
+ if (changed) {
+ mCallback.update();
+ }
+ }
+ }
+
+ @Override
+ public void routeRemoved(RouteInfo route) {
+ if (mInterfaceName.equals(route.getInterface())) {
+ maybeLog("routeRemoved", route);
+ boolean changed;
+ synchronized (this) {
+ changed = mLinkProperties.removeRoute(route);
+ }
+ if (changed) {
+ mCallback.update();
+ }
+ }
+ }
+
+ /**
+ * Returns a copy of this object's LinkProperties.
+ */
+ public synchronized LinkProperties getLinkProperties() {
+ return new LinkProperties(mLinkProperties);
+ }
+
+ public synchronized void clearLinkProperties() {
+ mLinkProperties.clear();
+ mLinkProperties.setInterfaceName(mInterfaceName);
+ }
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index de46804..15dfed1 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -89,6 +89,7 @@
android_util_Process.cpp \
android_util_StringBlock.cpp \
android_util_XmlBlock.cpp \
+ android/graphics/AndroidPicture.cpp \
android/graphics/AutoDecodeCancel.cpp \
android/graphics/Bitmap.cpp \
android/graphics/BitmapFactory.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 9383f4e..a7a1faad 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -159,6 +159,7 @@
extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_AndroidBidi(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
+extern int register_android_server_fingerprint_FingerprintService(JNIEnv* env);
extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
extern int register_android_server_Watchdog(JNIEnv* env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
@@ -244,9 +245,6 @@
mArgBlockLength(argBlockLength)
{
SkGraphics::Init();
- // this sets our preference for 16bit images during decode
- // in case the src is opaque and 24bit
- SkImageDecoder::SetDeviceConfig(SkBitmap::kRGB_565_Config);
// There is also a global font cache, but its budget is specified in code
// see SkFontHost_android.cpp
@@ -818,14 +816,16 @@
* Set profiler options
*/
if (libart) {
- // Number of seconds during profile runs.
+ // Whether or not the profiler should be enabled.
property_get("dalvik.vm.profiler", propBuf, "0");
if (propBuf[0] == '1') {
opt.optionString = "-Xenable-profiler";
mOptions.add(opt);
}
- property_get("dalvik.vm.profile.start-immediately", propBuf, "0");
+ // Whether the profile should start upon app startup or be delayed by some random offset
+ // (in seconds) that is bound between 0 and a fixed value.
+ property_get("dalvik.vm.profile.start-immed", propBuf, "0");
if (propBuf[0] == '1') {
opt.optionString = "-Xprofile-start-immediately";
mOptions.add(opt);
@@ -1329,6 +1329,7 @@
REG_JNI(register_android_media_ToneGenerator),
REG_JNI(register_android_opengl_classes),
+ REG_JNI(register_android_server_fingerprint_FingerprintService),
REG_JNI(register_android_server_NetworkManagementSocketTagger),
REG_JNI(register_android_server_Watchdog),
REG_JNI(register_android_ddm_DdmHandleNativeHeap),
diff --git a/core/jni/android/graphics/AndroidPicture.cpp b/core/jni/android/graphics/AndroidPicture.cpp
new file mode 100644
index 0000000..5977ab2
--- /dev/null
+++ b/core/jni/android/graphics/AndroidPicture.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#include "AndroidPicture.h"
+#include "SkCanvas.h"
+#include "SkStream.h"
+
+AndroidPicture::AndroidPicture(const AndroidPicture* src) {
+ if (NULL != src) {
+ mWidth = src->width();
+ mHeight = src->height();
+ if (NULL != src->mPicture.get()) {
+ mPicture.reset(SkRef(src->mPicture.get()));
+ } if (NULL != src->mRecorder.get()) {
+ mPicture.reset(src->makePartialCopy());
+ }
+ } else {
+ mWidth = 0;
+ mHeight = 0;
+ }
+}
+
+SkCanvas* AndroidPicture::beginRecording(int width, int height) {
+ mPicture.reset(NULL);
+ mRecorder.reset(new SkPictureRecorder);
+ mWidth = width;
+ mHeight = height;
+ return mRecorder->beginRecording(width, height, NULL, 0);
+}
+
+void AndroidPicture::endRecording() {
+ if (NULL != mRecorder.get()) {
+ mPicture.reset(mRecorder->endRecording());
+ mRecorder.reset(NULL);
+ }
+}
+
+int AndroidPicture::width() const {
+ if (NULL != mPicture.get()) {
+ SkASSERT(mPicture->width() == mWidth);
+ SkASSERT(mPicture->height() == mHeight);
+ }
+
+ return mWidth;
+}
+
+int AndroidPicture::height() const {
+ if (NULL != mPicture.get()) {
+ SkASSERT(mPicture->width() == mWidth);
+ SkASSERT(mPicture->height() == mHeight);
+ }
+
+ return mHeight;
+}
+
+AndroidPicture* AndroidPicture::CreateFromStream(SkStream* stream) {
+ AndroidPicture* newPict = new AndroidPicture;
+
+ newPict->mPicture.reset(SkPicture::CreateFromStream(stream));
+ if (NULL != newPict->mPicture.get()) {
+ newPict->mWidth = newPict->mPicture->width();
+ newPict->mHeight = newPict->mPicture->height();
+ }
+
+ return newPict;
+}
+
+void AndroidPicture::serialize(SkWStream* stream) const {
+ if (NULL != mRecorder.get()) {
+ SkAutoTDelete<SkPicture> tempPict(this->makePartialCopy());
+ tempPict->serialize(stream);
+ } else if (NULL != mPicture.get()) {
+ mPicture->serialize(stream);
+ } else {
+ SkPicture empty;
+ empty.serialize(stream);
+ }
+}
+
+void AndroidPicture::draw(SkCanvas* canvas) {
+ if (NULL != mRecorder.get()) {
+ this->endRecording();
+ SkASSERT(NULL != mPicture.get());
+ }
+ if (NULL != mPicture.get()) {
+ // TODO: remove this const_cast once pictures are immutable
+ const_cast<SkPicture*>(mPicture.get())->draw(canvas);
+ }
+}
+
+SkPicture* AndroidPicture::makePartialCopy() const {
+ SkASSERT(NULL != mRecorder.get());
+
+ SkPictureRecorder reRecorder;
+
+ SkCanvas* canvas = reRecorder.beginRecording(mWidth, mHeight, NULL, 0);
+ mRecorder->partialReplay(canvas);
+ return reRecorder.endRecording();
+}
diff --git a/core/jni/android/graphics/AndroidPicture.h b/core/jni/android/graphics/AndroidPicture.h
new file mode 100644
index 0000000..f434941
--- /dev/null
+++ b/core/jni/android/graphics/AndroidPicture.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_PICTURE_H
+#define ANDROID_PICTURE_H
+
+#include "SkPicture.h"
+#include "SkPictureRecorder.h"
+#include "SkRefCnt.h"
+#include "SkTemplates.h"
+
+class SkCanvas;
+class SkPicture;
+class SkPictureRecorder;
+class SkStream;
+class SkWStream;
+
+// Skia's SkPicture class has been split into an SkPictureRecorder
+// and an SkPicture. AndroidPicture recreates the functionality
+// of the old SkPicture interface by flip-flopping between the two
+// new classes.
+class AndroidPicture {
+public:
+ explicit AndroidPicture(const AndroidPicture* src = NULL);
+
+ SkCanvas* beginRecording(int width, int height);
+
+ void endRecording();
+
+ int width() const;
+
+ int height() const;
+
+ static AndroidPicture* CreateFromStream(SkStream* stream);
+
+ void serialize(SkWStream* stream) const;
+
+ void draw(SkCanvas* canvas);
+
+private:
+ int mWidth;
+ int mHeight;
+ SkAutoTUnref<const SkPicture> mPicture;
+ SkAutoTDelete<SkPictureRecorder> mRecorder;
+
+ // Make a copy of a picture that is in the midst of being recorded. The
+ // resulting picture will have balanced saves and restores.
+ SkPicture* makePartialCopy() const;
+};
+#endif // ANDROID_PICTURE_H
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 0328517..9998995 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -361,24 +361,50 @@
}
static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
- jint width, jint height, jint configHandle, jint allocSize) {
+ jint width, jint height, jint configHandle, jint allocSize,
+ jboolean requestPremul) {
SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);
- if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) {
+ SkColorType colorType = SkBitmapConfigToColorType(config);
+
+ // ARGB_4444 is a deprecated format, convert automatically to 8888
+ if (colorType == kARGB_4444_SkColorType) {
+ colorType = kN32_SkColorType;
+ }
+
+ if (width * height * SkColorTypeBytesPerPixel(colorType) > allocSize) {
// done in native as there's no way to get BytesPerPixel in Java
doThrowIAE(env, "Bitmap not large enough to support new configuration");
return;
}
SkPixelRef* ref = bitmap->pixelRef();
- SkSafeRef(ref);
- bitmap->setConfig(config, width, height);
+ ref->ref();
+ SkAlphaType alphaType;
+ if (bitmap->colorType() != kRGB_565_SkColorType
+ && bitmap->alphaType() == kOpaque_SkAlphaType) {
+ // If the original bitmap was set to opaque, keep that setting, unless it
+ // was 565, which is required to be opaque.
+ alphaType = kOpaque_SkAlphaType;
+ } else {
+ // Otherwise respect the premultiplied request.
+ alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
+ }
+ bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType));
+ // FIXME: Skia thinks of an SkPixelRef as having a constant SkImageInfo (except for
+ // its alphatype), so it would make more sense from Skia's perspective to create a
+ // new SkPixelRef. That said, libhwui uses the pointer to the SkPixelRef as a key
+ // for its cache, so it won't realize this is the same Java Bitmap.
+ SkImageInfo& info = const_cast<SkImageInfo&>(ref->info());
+ // Use the updated from the SkBitmap, which may have corrected an invalid alphatype.
+ // (e.g. 565 non-opaque)
+ info = bitmap->info();
bitmap->setPixelRef(ref);
// notifyPixelsChanged will increment the generation ID even though the actual pixel data
// hasn't been touched. This signals the renderer that the bitmap (including width, height,
- // and config) has changed.
+ // colortype and alphatype) has changed.
ref->notifyPixelsChanged();
- SkSafeUnref(ref);
+ ref->unref();
}
// These must match the int values in Bitmap.java
@@ -799,7 +825,7 @@
(void*)Bitmap_copy },
{ "nativeDestructor", "(J)V", (void*)Bitmap_destructor },
{ "nativeRecycle", "(J)Z", (void*)Bitmap_recycle },
- { "nativeReconfigure", "(JIIII)V", (void*)Bitmap_reconfigure },
+ { "nativeReconfigure", "(JIIIIZ)V", (void*)Bitmap_reconfigure },
{ "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
(void*)Bitmap_compress },
{ "nativeErase", "(JI)V", (void*)Bitmap_erase },
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 8b75e7d..4584c46 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -19,11 +19,14 @@
#include <android_runtime/AndroidRuntime.h>
#include "SkCanvas.h"
+#include "SkClipStack.h"
#include "SkDevice.h"
+#include "SkDeque.h"
#include "SkDrawFilter.h"
#include "SkGraphics.h"
#include "SkPorterDuff.h"
#include "SkShader.h"
+#include "SkTArray.h"
#include "SkTemplates.h"
#ifdef USE_MINIKIN
@@ -43,25 +46,6 @@
namespace android {
-// Holds an SkCanvas reference plus additional native data.
-class NativeCanvasWrapper {
-public:
- NativeCanvasWrapper(SkCanvas* canvas)
- : mCanvas(canvas) { }
-
- SkCanvas* getCanvas() const {
- return mCanvas.get();
- }
-
- void setCanvas(SkCanvas* canvas) {
- SkASSERT(canvas);
- mCanvas.reset(canvas);
- }
-
-private:
- SkAutoTUnref<SkCanvas> mCanvas;
-};
-
class ClipCopier : public SkCanvas::ClipVisitor {
public:
ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {}
@@ -80,6 +64,155 @@
SkCanvas* m_dstCanvas;
};
+// Holds an SkCanvas reference plus additional native data.
+class NativeCanvasWrapper {
+private:
+ struct SaveRec {
+ int saveCount;
+ SkCanvas::SaveFlags saveFlags;
+ };
+
+public:
+ NativeCanvasWrapper(SkCanvas* canvas)
+ : mCanvas(canvas)
+ , mSaveStack(NULL) {
+ SkASSERT(canvas);
+ }
+
+ ~NativeCanvasWrapper() {
+ delete mSaveStack;
+ }
+
+ SkCanvas* getCanvas() const {
+ return mCanvas.get();
+ }
+
+ void setCanvas(SkCanvas* canvas) {
+ SkASSERT(canvas);
+ mCanvas.reset(canvas);
+
+ delete mSaveStack;
+ mSaveStack = NULL;
+ }
+
+ int save(SkCanvas::SaveFlags flags) {
+ int count = mCanvas->save();
+ recordPartialSave(flags);
+ return count;
+ }
+
+ int saveLayer(const SkRect* bounds, const SkPaint* paint,
+ SkCanvas::SaveFlags flags) {
+ int count = mCanvas->saveLayer(bounds, paint,
+ static_cast<SkCanvas::SaveFlags>(flags | SkCanvas::kMatrixClip_SaveFlag));
+ recordPartialSave(flags);
+ return count;
+ }
+
+ int saveLayerAlpha(const SkRect* bounds, U8CPU alpha,
+ SkCanvas::SaveFlags flags) {
+ int count = mCanvas->saveLayerAlpha(bounds, alpha,
+ static_cast<SkCanvas::SaveFlags>(flags | SkCanvas::kMatrixClip_SaveFlag));
+ recordPartialSave(flags);
+ return count;
+ }
+
+ void restore() {
+ const SaveRec* rec = (NULL == mSaveStack)
+ ? NULL
+ : static_cast<SaveRec*>(mSaveStack->back());
+ int currentSaveCount = mCanvas->getSaveCount() - 1;
+ SkASSERT(NULL == rec || currentSaveCount >= rec->saveCount);
+
+ if (NULL == rec || rec->saveCount != currentSaveCount) {
+ // Fast path - no record for this frame.
+ mCanvas->restore();
+ return;
+ }
+
+ bool preserveMatrix = !(rec->saveFlags & SkCanvas::kMatrix_SaveFlag);
+ bool preserveClip = !(rec->saveFlags & SkCanvas::kClip_SaveFlag);
+
+ SkMatrix savedMatrix;
+ if (preserveMatrix) {
+ savedMatrix = mCanvas->getTotalMatrix();
+ }
+
+ SkTArray<SkClipStack::Element> savedClips;
+ if (preserveClip) {
+ saveClipsForFrame(savedClips, currentSaveCount);
+ }
+
+ mCanvas->restore();
+
+ if (preserveMatrix) {
+ mCanvas->setMatrix(savedMatrix);
+ }
+
+ if (preserveClip && !savedClips.empty()) {
+ applyClips(savedClips);
+ }
+
+ mSaveStack->pop_back();
+ }
+
+private:
+ void recordPartialSave(SkCanvas::SaveFlags flags) {
+ // A partial save is a save operation which doesn't capture the full canvas state.
+ // (either kMatrix_SaveFlags or kClip_SaveFlag is missing).
+
+ // Mask-out non canvas state bits.
+ flags = static_cast<SkCanvas::SaveFlags>(flags & SkCanvas::kMatrixClip_SaveFlag);
+
+ if (SkCanvas::kMatrixClip_SaveFlag == flags) {
+ // not a partial save.
+ return;
+ }
+
+ if (NULL == mSaveStack) {
+ mSaveStack = new SkDeque(sizeof(struct SaveRec), 8);
+ }
+
+ SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back());
+ // Store the save counter in the SkClipStack domain.
+ // (0-based, equal to the number of save ops on the stack).
+ rec->saveCount = mCanvas->getSaveCount() - 1;
+ rec->saveFlags = flags;
+ }
+
+ void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips,
+ int frameSaveCount) {
+ SkClipStack::Iter clipIterator(*mCanvas->getClipStack(),
+ SkClipStack::Iter::kTop_IterStart);
+ while (const SkClipStack::Element* elem = clipIterator.next()) {
+ if (elem->getSaveCount() < frameSaveCount) {
+ // done with the current frame.
+ break;
+ }
+ SkASSERT(elem->getSaveCount() == frameSaveCount);
+ clips.push_back(*elem);
+ }
+ }
+
+ void applyClips(const SkTArray<SkClipStack::Element>& clips) {
+ ClipCopier clipCopier(mCanvas);
+
+ // The clip stack stores clips in device space.
+ SkMatrix origMatrix = mCanvas->getTotalMatrix();
+ mCanvas->resetMatrix();
+
+ // We pushed the clips in reverse order.
+ for (int i = clips.count() - 1; i >= 0; --i) {
+ clips[i].replay(&clipCopier);
+ }
+
+ mCanvas->setMatrix(origMatrix);
+ }
+
+ SkAutoTUnref<SkCanvas> mCanvas;
+ SkDeque* mSaveStack; // lazily allocated, tracks partial saves.
+};
+
// Returns true if the SkCanvas's clip is non-empty.
static jboolean hasNonEmptyClip(const SkCanvas& canvas) {
bool emptyClip = canvas.isClipEmpty();
@@ -88,11 +221,15 @@
class SkCanvasGlue {
public:
+ // Get the native wrapper for a given handle.
+ static inline NativeCanvasWrapper* getNativeWrapper(jlong nativeHandle) {
+ SkASSERT(nativeHandle);
+ return reinterpret_cast<NativeCanvasWrapper*>(nativeHandle);
+ }
// Get the SkCanvas for a given native handle.
static inline SkCanvas* getNativeCanvas(jlong nativeHandle) {
- SkASSERT(nativeHandle);
- NativeCanvasWrapper* wrapper = reinterpret_cast<NativeCanvasWrapper*>(nativeHandle);
+ NativeCanvasWrapper* wrapper = getNativeWrapper(nativeHandle);
SkCanvas* canvas = wrapper->getCanvas();
SkASSERT(canvas);
@@ -186,56 +323,56 @@
}
static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) {
- SkCanvas* canvas = getNativeCanvas(canvasHandle);
+ NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
- return static_cast<jint>(canvas->save(flags));
+ return static_cast<jint>(wrapper->save(flags));
}
static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle,
jfloat l, jfloat t, jfloat r, jfloat b,
- jlong paintHandle, jint flags) {
- SkCanvas* canvas = getNativeCanvas(canvasHandle);
+ jlong paintHandle, jint flagsHandle) {
+ NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+ SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
SkRect bounds;
bounds.set(l, t, r, b);
- int result = canvas->saveLayer(&bounds, paint,
- static_cast<SkCanvas::SaveFlags>(flags));
- return static_cast<jint>(result);
+ return static_cast<jint>(wrapper->saveLayer(&bounds, paint, flags));
}
static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle,
jfloat l, jfloat t, jfloat r, jfloat b,
- jint alpha, jint flags) {
- SkCanvas* canvas = getNativeCanvas(canvasHandle);
+ jint alpha, jint flagsHandle) {
+ NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
+ SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle);
SkRect bounds;
bounds.set(l, t, r, b);
- int result = canvas->saveLayerAlpha(&bounds, alpha,
- static_cast<SkCanvas::SaveFlags>(flags));
- return static_cast<jint>(result);
+ return static_cast<jint>(wrapper->saveLayerAlpha(&bounds, alpha, flags));
}
static void restore(JNIEnv* env, jobject, jlong canvasHandle) {
- SkCanvas* canvas = getNativeCanvas(canvasHandle);
- if (canvas->getSaveCount() <= 1) { // cannot restore anymore
+ NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
+ if (wrapper->getCanvas()->getSaveCount() <= 1) { // cannot restore anymore
doThrowISE(env, "Underflow in restore");
return;
}
- canvas->restore();
+ wrapper->restore();
}
static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) {
- SkCanvas* canvas = getNativeCanvas(canvasHandle);
- return static_cast<jint>(canvas->getSaveCount());
+ return static_cast<jint>(getNativeCanvas(canvasHandle)->getSaveCount());
}
static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle,
jint restoreCount) {
- SkCanvas* canvas = getNativeCanvas(canvasHandle);
+ NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle);
if (restoreCount < 1) {
doThrowIAE(env, "Underflow in restoreToCount");
return;
}
- canvas->restoreToCount(restoreCount);
+
+ while (wrapper->getCanvas()->getSaveCount() > restoreCount) {
+ wrapper->restore();
+ }
}
static void translate(JNIEnv*, jobject, jlong canvasHandle,
@@ -432,12 +569,11 @@
canvas->drawRectCoords(left, top, right, bottom, *paint);
}
- static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jobject joval,
- jlong paintHandle) {
+ static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
+ jfloat right, jfloat bottom, jlong paintHandle) {
SkCanvas* canvas = getNativeCanvas(canvasHandle);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
- SkRect oval;
- GraphicsJNI::jrectf_to_rect(env, joval, &oval);
+ SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
canvas->drawOval(oval, *paint);
}
@@ -448,13 +584,12 @@
canvas->drawCircle(cx, cy, radius, *paint);
}
- static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jobject joval,
- jfloat startAngle, jfloat sweepAngle,
- jboolean useCenter, jlong paintHandle) {
+ static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
+ jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle, jboolean useCenter,
+ jlong paintHandle) {
SkCanvas* canvas = getNativeCanvas(canvasHandle);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
- SkRect oval;
- GraphicsJNI::jrectf_to_rect(env, joval, &oval);
+ SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
canvas->drawArc(oval, startAngle, sweepAngle, useCenter, *paint);
}
@@ -745,26 +880,26 @@
static void drawText___CIIFFIPaintTypeface(JNIEnv* env, jobject, jlong canvasHandle,
jcharArray text, jint index, jint count,
- jfloat x, jfloat y, jint flags,
+ jfloat x, jfloat y, jint bidiFlags,
jlong paintHandle, jlong typefaceHandle) {
SkCanvas* canvas = getNativeCanvas(canvasHandle);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
jchar* textArray = env->GetCharArrayElements(text, NULL);
- drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint, typeface);
+ drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, bidiFlags, paint, typeface);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
static void drawText__StringIIFFIPaintTypeface(JNIEnv* env, jobject,
jlong canvasHandle, jstring text,
jint start, jint end,
- jfloat x, jfloat y, jint flags,
+ jfloat x, jfloat y, jint bidiFlags,
jlong paintHandle, jlong typefaceHandle) {
SkCanvas* canvas = getNativeCanvas(canvasHandle);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
const jchar* textArray = env->GetStringChars(text, NULL);
- drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint, typeface);
+ drawTextWithGlyphs(canvas, textArray, start, end, x, y, bidiFlags, paint, typeface);
env->ReleaseStringChars(text, textArray);
}
@@ -776,13 +911,12 @@
: layout(layout), canvas(canvas), x(x), y(y), paint(paint), glyphs(glyphs),
pos(pos) { }
- void operator()(SkTypeface* t, size_t start, size_t end) {
+ void operator()(size_t start, size_t end) {
for (size_t i = start; i < end; i++) {
glyphs[i] = layout.getGlyphId(i);
pos[i].fX = x + layout.getX(i);
pos[i].fY = y + layout.getY(i);
}
- paint->setTypeface(t);
canvas->drawPosText(glyphs + start, (end - start) << 1, pos + start, *paint);
}
private:
@@ -805,7 +939,7 @@
paint->setTextAlign(SkPaint::kLeft_Align);
paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
DrawTextFunctor f(layout, canvas, x, y, paint, glyphs, pos);
- MinikinUtils::forFontRun(layout, f);
+ MinikinUtils::forFontRun(layout, paint, f);
doDrawTextDecorations(canvas, x, y, layout.getAdvance(), paint);
paint->setTextAlign(align);
delete[] glyphs;
@@ -815,24 +949,25 @@
static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
int start, int end,
- jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) {
+ jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) {
jint count = end - start;
- drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint, typeface);
+ drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, bidiFlags, paint,
+ typeface);
}
static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
int start, int count, int contextCount,
- jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) {
+ jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) {
#ifdef USE_MINIKIN
Layout layout;
- std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface);
+ std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
layout.doLayout(textArray, start, count, contextCount, css);
drawGlyphsToSkia(canvas, paint, layout, x, y);
#else
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
- textArray, start, count, contextCount, flags);
+ textArray, start, count, contextCount, bidiFlags);
if (value == NULL) {
return;
}
@@ -843,7 +978,8 @@
x -= value->getTotalAdvance();
}
paint->setTextAlign(SkPaint::kLeft_Align);
- doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, flags, paint);
+ doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(),
+ x, y, paint);
doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint);
paint->setTextAlign(align);
#endif
@@ -854,42 +990,37 @@
#define kStdUnderline_Offset (1.0f / 9.0f)
#define kStdUnderline_Thickness (1.0f / 18.0f)
-static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat length, SkPaint* paint) {
- uint32_t flags;
- SkDrawFilter* drawFilter = canvas->getDrawFilter();
- if (drawFilter) {
- SkPaint paintCopy(*paint);
- drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type);
- flags = paintCopy.getFlags();
- } else {
- flags = paint->getFlags();
- }
- if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
- SkScalar left = x;
- SkScalar right = x + length;
- float textSize = paint->getTextSize();
- float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
- if (flags & SkPaint::kUnderlineText_Flag) {
- SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth;
- SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth;
- canvas->drawRectCoords(left, top, right, bottom, *paint);
+ static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat length,
+ SkPaint* paint) {
+ uint32_t flags;
+ SkDrawFilter* drawFilter = canvas->getDrawFilter();
+ if (drawFilter) {
+ SkPaint paintCopy(*paint);
+ drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type);
+ flags = paintCopy.getFlags();
+ } else {
+ flags = paint->getFlags();
}
- if (flags & SkPaint::kStrikeThruText_Flag) {
- SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth;
- SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth;
- canvas->drawRectCoords(left, top, right, bottom, *paint);
+ if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
+ SkScalar left = x;
+ SkScalar right = x + length;
+ float textSize = paint->getTextSize();
+ float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
+ if (flags & SkPaint::kUnderlineText_Flag) {
+ SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth;
+ SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth;
+ canvas->drawRectCoords(left, top, right, bottom, *paint);
+ }
+ if (flags & SkPaint::kStrikeThruText_Flag) {
+ SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth;
+ SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth;
+ canvas->drawRectCoords(left, top, right, bottom, *paint);
+ }
}
}
-}
-
- static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count,
- jfloat x, jfloat y, int flags, SkPaint* paint) {
- // Beware: this needs Glyph encoding (already done on the Paint constructor)
- canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint);
- }
static void doDrawGlyphsPos(SkCanvas* canvas, const jchar* glyphArray, const jfloat* posArray,
- int index, int count, jfloat x, jfloat y, int flags, SkPaint* paint) {
+ int index, int count, jfloat x, jfloat y, SkPaint* paint) {
SkPoint* posPtr = new SkPoint[count];
for (int indx = 0; indx < count; indx++) {
posPtr[indx].fX = x + posArray[indx * 2];
@@ -899,33 +1030,35 @@
delete[] posPtr;
}
- static void drawTextRun___CIIIIFFIPaintTypeface(
+ static void drawTextRun___CIIIIFFZPaintTypeface(
JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
jint count, jint contextIndex, jint contextCount,
- jfloat x, jfloat y, jint dirFlags, jlong paintHandle, jlong typefaceHandle) {
+ jfloat x, jfloat y, jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
SkCanvas* canvas = getNativeCanvas(canvasHandle);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+ int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
jchar* chars = env->GetCharArrayElements(text, NULL);
drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
- count, contextCount, x, y, dirFlags, paint, typeface);
+ count, contextCount, x, y, bidiFlags, paint, typeface);
env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
}
- static void drawTextRun__StringIIIIFFIPaintTypeface(
+ static void drawTextRun__StringIIIIFFZPaintTypeface(
JNIEnv* env, jobject obj, jlong canvasHandle, jstring text, jint start,
jint end, jint contextStart, jint contextEnd,
- jfloat x, jfloat y, jint dirFlags, jlong paintHandle, jlong typefaceHandle) {
+ jfloat x, jfloat y, jboolean isRtl, jlong paintHandle, jlong typefaceHandle) {
SkCanvas* canvas = getNativeCanvas(canvasHandle);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+ int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
jint count = end - start;
jint contextCount = contextEnd - contextStart;
const jchar* chars = env->GetStringChars(text, NULL);
drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
- count, contextCount, x, y, dirFlags, paint, typeface);
+ count, contextCount, x, y, bidiFlags, paint, typeface);
env->ReleaseStringChars(text, chars);
}
@@ -1106,11 +1239,9 @@
{"native_drawLines", "(J[FIIJ)V", (void*) SkCanvasGlue::drawLines},
{"native_drawLine","(JFFFFJ)V", (void*) SkCanvasGlue::drawLine__FFFFPaint},
{"native_drawRect","(JFFFFJ)V", (void*) SkCanvasGlue::drawRect__FFFFPaint},
- {"native_drawOval","(JLandroid/graphics/RectF;J)V",
- (void*) SkCanvasGlue::drawOval},
+ {"native_drawOval","(JFFFFJ)V", (void*) SkCanvasGlue::drawOval},
{"native_drawCircle","(JFFFJ)V", (void*) SkCanvasGlue::drawCircle},
- {"native_drawArc","(JLandroid/graphics/RectF;FFZJ)V",
- (void*) SkCanvasGlue::drawArc},
+ {"native_drawArc","(JFFFFFFZJ)V", (void*) SkCanvasGlue::drawArc},
{"native_drawRoundRect","(JFFFFFFJ)V",
(void*) SkCanvasGlue::drawRoundRect},
{"native_drawPath","(JJJ)V", (void*) SkCanvasGlue::drawPath},
@@ -1132,10 +1263,10 @@
(void*) SkCanvasGlue::drawText___CIIFFIPaintTypeface},
{"native_drawText","(JLjava/lang/String;IIFFIJJ)V",
(void*) SkCanvasGlue::drawText__StringIIFFIPaintTypeface},
- {"native_drawTextRun","(J[CIIIIFFIJJ)V",
- (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaintTypeface},
- {"native_drawTextRun","(JLjava/lang/String;IIIIFFIJJ)V",
- (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaintTypeface},
+ {"native_drawTextRun","(J[CIIIIFFZJJ)V",
+ (void*) SkCanvasGlue::drawTextRun___CIIIIFFZPaintTypeface},
+ {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V",
+ (void*) SkCanvasGlue::drawTextRun__StringIIIIFFZPaintTypeface},
{"native_drawPosText","(J[CII[FJ)V",
(void*) SkCanvasGlue::drawPosText___CII_FPaint},
{"native_drawPosText","(JLjava/lang/String;[FJ)V",
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 64ad223..a4337ccc 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -3,6 +3,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "GraphicsJNI.h"
+#include "AndroidPicture.h"
#include "SkCanvas.h"
#include "SkDevice.h"
@@ -345,13 +346,13 @@
return p;
}
-SkPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture)
+AndroidPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture)
{
SkASSERT(env);
SkASSERT(picture);
SkASSERT(env->IsInstanceOf(picture, gPicture_class));
jlong pictureHandle = env->GetLongField(picture, gPicture_nativeInstanceID);
- SkPicture* p = reinterpret_cast<SkPicture*>(pictureHandle);
+ AndroidPicture* p = reinterpret_cast<AndroidPicture*>(pictureHandle);
SkASSERT(p);
return p;
}
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 73dd11b..2e2f920 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -14,7 +14,7 @@
class SkBitmapRegionDecoder;
class SkCanvas;
class SkPaint;
-class SkPicture;
+class AndroidPicture;
class GraphicsJNI {
public:
@@ -50,7 +50,7 @@
static SkPaint* getNativePaint(JNIEnv*, jobject paint);
static android::TypefaceImpl* getNativeTypeface(JNIEnv*, jobject paint);
static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap);
- static SkPicture* getNativePicture(JNIEnv*, jobject picture);
+ static AndroidPicture* getNativePicture(JNIEnv*, jobject picture);
static SkRegion* getNativeRegion(JNIEnv*, jobject region);
// Given the 'native' long held by the Rasterizer.java object, return a
diff --git a/core/jni/android/graphics/MinikinSkia.cpp b/core/jni/android/graphics/MinikinSkia.cpp
index 2b96f1b..25eb941 100644
--- a/core/jni/android/graphics/MinikinSkia.cpp
+++ b/core/jni/android/graphics/MinikinSkia.cpp
@@ -43,13 +43,14 @@
return !!glyph;
}
-static void MinikinFontSkia_SetSkiaPaint(SkTypeface* typeface, SkPaint* skPaint, const MinikinPaint& paint) {
- skPaint->setTypeface(typeface);
+static void MinikinFontSkia_SetSkiaPaint(const MinikinFont* font, SkPaint* skPaint, const MinikinPaint& paint) {
skPaint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
skPaint->setTextSize(paint.size);
skPaint->setTextScaleX(paint.scaleX);
skPaint->setTextSkewX(paint.skewX);
MinikinFontSkia::unpackPaintFlags(skPaint, paint.paintFlags);
+ // Apply font fakery on top of user-supplied flags.
+ MinikinFontSkia::populateSkPaint(skPaint, font, paint.fakery);
}
float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id,
@@ -57,7 +58,7 @@
SkPaint skPaint;
uint16_t glyph16 = glyph_id;
SkScalar skWidth;
- MinikinFontSkia_SetSkiaPaint(mTypeface, &skPaint, paint);
+ MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
skPaint.getTextWidths(&glyph16, sizeof(glyph16), &skWidth, NULL);
#ifdef VERBOSE
ALOGD("width for typeface %d glyph %d = %f", mTypeface->uniqueID(), glyph_id, skWidth);
@@ -70,7 +71,7 @@
SkPaint skPaint;
uint16_t glyph16 = glyph_id;
SkRect skBounds;
- MinikinFontSkia_SetSkiaPaint(mTypeface, &skPaint, paint);
+ MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
skPaint.getTextWidths(&glyph16, sizeof(glyph16), NULL, &skBounds);
bounds->mLeft = skBounds.fLeft;
bounds->mTop = skBounds.fTop;
@@ -90,7 +91,7 @@
}
}
-SkTypeface *MinikinFontSkia::GetSkTypeface() {
+SkTypeface *MinikinFontSkia::GetSkTypeface() const {
return mTypeface;
}
@@ -115,4 +116,12 @@
paint->setHinting(static_cast<SkPaint::Hinting>(paintFlags >> 16));
}
+void MinikinFontSkia::populateSkPaint(SkPaint* paint, const MinikinFont* font, FontFakery fakery) {
+ paint->setTypeface(reinterpret_cast<const MinikinFontSkia*>(font)->GetSkTypeface());
+ paint->setFakeBoldText(paint->isFakeBoldText() || fakery.isFakeBold());
+ if (fakery.isFakeItalic()) {
+ paint->setTextSkewX(paint->getTextSkewX() - 0.25f);
+ }
+}
+
}
diff --git a/core/jni/android/graphics/MinikinSkia.h b/core/jni/android/graphics/MinikinSkia.h
index 0452c57..ac4d2a0 100644
--- a/core/jni/android/graphics/MinikinSkia.h
+++ b/core/jni/android/graphics/MinikinSkia.h
@@ -36,10 +36,13 @@
int32_t GetUniqueId() const;
- SkTypeface *GetSkTypeface();
+ SkTypeface* GetSkTypeface() const;
static uint32_t packPaintFlags(const SkPaint* paint);
static void unpackPaintFlags(SkPaint* paint, uint32_t paintFlags);
+
+ // set typeface and fake bold/italic parameters
+ static void populateSkPaint(SkPaint* paint, const MinikinFont* font, FontFakery fakery);
private:
SkTypeface *mTypeface;
};
diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h
index ea7eb5d..a96c6b1 100644
--- a/core/jni/android/graphics/MinikinUtils.h
+++ b/core/jni/android/graphics/MinikinUtils.h
@@ -36,23 +36,30 @@
static float xOffsetForTextAlign(SkPaint* paint, const Layout& layout);
- // f is a functor of type void f(SkTypeface *, size_t start, size_t end);
+ // f is a functor of type void f(size_t start, size_t end);
template <typename F>
- static void forFontRun(const Layout& layout, F& f) {
- SkTypeface* lastFace = NULL;
+ static void forFontRun(const Layout& layout, SkPaint* paint, F& f) {
+ float saveSkewX = paint->getTextSkewX();
+ bool savefakeBold = paint->isFakeBoldText();
+ MinikinFont* curFont = NULL;
size_t start = 0;
size_t nGlyphs = layout.nGlyphs();
for (size_t i = 0; i < nGlyphs; i++) {
- MinikinFontSkia* mfs = static_cast<MinikinFontSkia*>(layout.getFont(i));
- SkTypeface* skFace = mfs->GetSkTypeface();
- if (i > 0 && skFace != lastFace) {
- f(lastFace, start, i);
+ MinikinFont* nextFont = layout.getFont(i);
+ if (i > 0 && nextFont != curFont) {
+ MinikinFontSkia::populateSkPaint(paint, curFont, layout.getFakery(start));
+ f(start, i);
+ paint->setTextSkewX(saveSkewX);
+ paint->setFakeBoldText(savefakeBold);
start = i;
}
- lastFace = skFace;
+ curFont = nextFont;
}
if (nGlyphs > start) {
- f(lastFace, start, nGlyphs);
+ MinikinFontSkia::populateSkPaint(paint, curFont, layout.getFakery(start));
+ f(start, nGlyphs);
+ paint->setTextSkewX(saveSkewX);
+ paint->setFakeBoldText(savefakeBold);
}
}
};
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 24731ac..d07b154 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -439,10 +439,19 @@
#ifdef USE_MINIKIN
TypefaceImpl* typeface = GraphicsJNI::getNativeTypeface(env, jpaint);
typeface = TypefaceImpl_resolveDefault(typeface);
- MinikinFont* baseFont = typeface->fFontCollection->baseFont(typeface->fStyle);
- paint->setTypeface(reinterpret_cast<MinikinFontSkia*>(baseFont)->GetSkTypeface());
+ FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
+ float saveSkewX = paint->getTextSkewX();
+ bool savefakeBold = paint->isFakeBoldText();
+ MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
#endif
SkScalar spacing = paint->getFontMetrics(metrics);
+#ifdef USE_MINIKIN
+ // The populateSkPaint call may have changed fake bold / text skew
+ // because we want to measure with those effects applied, so now
+ // restore the original settings.
+ paint->setTextSkewX(saveSkewX);
+ paint->setFakeBoldText(savefakeBold);
+#endif
SkPaintOptionsAndroid paintOpts = paint->getPaintOptionsAndroid();
if (paintOpts.getFontVariant() == SkPaintOptionsAndroid::kElegant_Variant) {
SkScalar size = paint->getTextSize();
@@ -698,7 +707,7 @@
}
static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, TypefaceImpl* typeface, const jchar *text,
- jint start, jint count, jint contextCount, jint flags,
+ jint start, jint count, jint contextCount, jboolean isRtl,
jfloatArray advances, jint advancesIndex) {
NPE_CHECK_RETURN_ZERO(env, paint);
NPE_CHECK_RETURN_ZERO(env, text);
@@ -720,14 +729,16 @@
jfloat* advancesArray = new jfloat[count];
jfloat totalAdvance = 0;
+ int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
+
#ifdef USE_MINIKIN
Layout layout;
- std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface);
+ std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
layout.doLayout(text, start, count, contextCount, css);
layout.getAdvances(advancesArray);
totalAdvance = layout.getAdvance();
#else
- TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags,
+ TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, bidiFlags,
advancesArray, &totalAdvance);
#endif
@@ -738,28 +749,28 @@
return totalAdvance;
}
- static jfloat getTextRunAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
+ static jfloat getTextRunAdvances___CIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
jlong typefaceHandle,
jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
- jint flags, jfloatArray advances, jint advancesIndex) {
+ jboolean isRtl, jfloatArray advances, jint advancesIndex) {
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
jchar* textArray = env->GetCharArrayElements(text, NULL);
jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextIndex,
- index - contextIndex, count, contextCount, flags, advances, advancesIndex);
+ index - contextIndex, count, contextCount, isRtl, advances, advancesIndex);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
return result;
}
- static jfloat getTextRunAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
+ static jfloat getTextRunAdvances__StringIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
jlong typefaceHandle,
- jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
+ jstring text, jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl,
jfloatArray advances, jint advancesIndex) {
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
const jchar* textArray = env->GetStringChars(text, NULL);
jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextStart,
- start - contextStart, end - start, contextEnd - contextStart, flags,
+ start - contextStart, end - start, contextEnd - contextStart, isRtl,
advances, advancesIndex);
env->ReleaseStringChars(text, textArray);
return result;
@@ -810,21 +821,21 @@
}
static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text,
- jint contextStart, jint contextCount, jint flags, jint offset, jint cursorOpt) {
+ jint contextStart, jint contextCount, jint dir, jint offset, jint cursorOpt) {
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
jchar* textArray = env->GetCharArrayElements(text, NULL);
- jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, flags,
+ jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, dir,
offset, cursorOpt);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
return result;
}
static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text,
- jint contextStart, jint contextEnd, jint flags, jint offset, jint cursorOpt) {
+ jint contextStart, jint contextEnd, jint dir, jint offset, jint cursorOpt) {
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
const jchar* textArray = env->GetStringChars(text, NULL);
jint result = doTextRunCursor(env, paint, textArray, contextStart,
- contextEnd - contextStart, flags, offset, cursorOpt);
+ contextEnd - contextStart, dir, offset, cursorOpt);
env->ReleaseStringChars(text, textArray);
return result;
}
@@ -837,13 +848,12 @@
: layout(layout), path(path), x(x), y(y), paint(paint), glyphs(glyphs), pos(pos) {
}
- void operator()(SkTypeface* t, size_t start, size_t end) {
+ void operator()(size_t start, size_t end) {
for (size_t i = start; i < end; i++) {
glyphs[i] = layout.getGlyphId(i);
pos[i].fX = x + layout.getX(i);
pos[i].fY = y + layout.getY(i);
}
- paint->setTypeface(t);
if (start == 0) {
paint->getPosTextPath(glyphs + start, (end - start) << 1, pos + start, path);
} else {
@@ -878,7 +888,7 @@
paint->setTextAlign(SkPaint::kLeft_Align);
paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
GetTextFunctor f(layout, path, x, y, paint, glyphs, pos);
- MinikinUtils::forFontRun(layout, f);
+ MinikinUtils::forFontRun(layout, paint, f);
paint->setTextAlign(align);
delete[] glyphs;
delete[] pos;
@@ -926,32 +936,62 @@
return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL);
}
- static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[],
+ static int breakText(JNIEnv* env, const SkPaint& paint, TypefaceImpl* typeface, const jchar text[],
int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
- SkPaint::TextBufferDirection tbd) {
+ SkPaint::TextBufferDirection textBufferDirection) {
+ size_t measuredCount = 0;
+ float measured = 0;
+
+#ifdef USE_MINIKIN
+ Layout layout;
+ std::string css = MinikinUtils::setLayoutProperties(&layout, &paint, bidiFlags, typeface);
+ layout.doLayout(text, 0, count, count, css);
+ float* advances = new float[count];
+ layout.getAdvances(advances);
+ const bool forwardScan = (textBufferDirection == SkPaint::kForward_TextBufferDirection);
+ for (int i = 0; i < count; i++) {
+ // traverse in the given direction
+ int index = forwardScan ? i : (count - i - 1);
+ float width = advances[index];
+ if (measured + width > maxWidth) {
+ break;
+ }
+ // properly handle clusters when scanning backwards
+ if (forwardScan || width != 0.0f) {
+ measuredCount = i + 1;
+ }
+ measured += width;
+ }
+ delete[] advances;
+#else
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
text, 0, count, count, bidiFlags);
if (value == NULL) {
return 0;
}
- SkScalar measured;
- size_t bytes = paint.breakText(value->getGlyphs(), value->getGlyphsCount() << 1,
- maxWidth, &measured, tbd);
+ SkScalar m;
+ size_t bytes = paint.breakText(value->getGlyphs(), value->getGlyphsCount() << 1,
+ maxWidth, &m, textBufferDirection);
SkASSERT((bytes & 1) == 0);
+ measuredCount = bytes >> 1;
+ measured = SkScalarToFloat(m);
+#endif
if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
jfloat* array = autoMeasured.ptr();
- array[0] = SkScalarToFloat(measured);
+ array[0] = measured;
}
- return bytes >> 1;
+ return measuredCount;
}
- static jint breakTextC(JNIEnv* env, jobject jpaint, jcharArray jtext,
+ static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray jtext,
jint index, jint count, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
- NPE_CHECK_RETURN_ZERO(env, jpaint);
NPE_CHECK_RETURN_ZERO(env, jtext);
+ SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+ TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+
SkPaint::TextBufferDirection tbd;
if (count < 0) {
tbd = SkPaint::kBackward_TextBufferDirection;
@@ -966,28 +1006,28 @@
return 0;
}
- SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
const jchar* text = env->GetCharArrayElements(jtext, NULL);
- count = breakText(env, *paint, text + index, count, maxWidth,
+ count = breakText(env, *paint, typeface, text + index, count, maxWidth,
bidiFlags, jmeasuredWidth, tbd);
env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
JNI_ABORT);
return count;
}
- static jint breakTextS(JNIEnv* env, jobject jpaint, jstring jtext,
+ static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext,
jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
- NPE_CHECK_RETURN_ZERO(env, jpaint);
NPE_CHECK_RETURN_ZERO(env, jtext);
+ SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+ TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+
SkPaint::TextBufferDirection tbd = forwards ?
SkPaint::kForward_TextBufferDirection :
SkPaint::kBackward_TextBufferDirection;
- SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
int count = env->GetStringLength(jtext);
const jchar* text = env->GetStringChars(jtext, NULL);
- count = breakText(env, *paint, text, count, maxWidth, bidiFlags, jmeasuredWidth, tbd);
+ count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, tbd);
env->ReleaseStringChars(jtext, text);
return count;
}
@@ -1098,14 +1138,14 @@
{"native_measureText","([CIII)F", (void*) SkPaintGlue::measureText_CIII},
{"native_measureText","(Ljava/lang/String;I)F", (void*) SkPaintGlue::measureText_StringI},
{"native_measureText","(Ljava/lang/String;III)F", (void*) SkPaintGlue::measureText_StringIII},
- {"native_breakText","([CIIFI[F)I", (void*) SkPaintGlue::breakTextC},
- {"native_breakText","(Ljava/lang/String;ZFI[F)I", (void*) SkPaintGlue::breakTextS},
+ {"native_breakText","(JJ[CIIFI[F)I", (void*) SkPaintGlue::breakTextC},
+ {"native_breakText","(JJLjava/lang/String;ZFI[F)I", (void*) SkPaintGlue::breakTextS},
{"native_getTextWidths","(JJ[CIII[F)I", (void*) SkPaintGlue::getTextWidths___CIII_F},
{"native_getTextWidths","(JJLjava/lang/String;III[F)I", (void*) SkPaintGlue::getTextWidths__StringIII_F},
- {"native_getTextRunAdvances","(JJ[CIIIII[FI)F",
- (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FI},
- {"native_getTextRunAdvances","(JJLjava/lang/String;IIIII[FI)F",
- (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI},
+ {"native_getTextRunAdvances","(JJ[CIIIIZ[FI)F",
+ (void*) SkPaintGlue::getTextRunAdvances___CIIIIZ_FI},
+ {"native_getTextRunAdvances","(JJLjava/lang/String;IIIIZ[FI)F",
+ (void*) SkPaintGlue::getTextRunAdvances__StringIIIIZ_FI},
{"native_getTextGlyphs","(JLjava/lang/String;IIIII[C)I",
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index 420a17f..6ef1d2c 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -2,22 +2,22 @@
**
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
// This file was generated from the C++ include file: SkPath.h
// Any changes made to this file will be discarded by the build.
-// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
+// To change this file, either edit the include, or device/tools/gluemaker/main.cpp,
// or one of the auxilary file specifications in device/tools/gluemaker.
#include "jni.h"
@@ -92,7 +92,7 @@
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
return obj->isEmpty();
}
-
+
static jboolean isRect(JNIEnv* env, jobject clazz, jlong objHandle, jobject jrect) {
SkRect rect;
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
@@ -100,65 +100,66 @@
GraphicsJNI::rect_to_jrectf(rect, env, jrect);
return result;
}
-
+
static void computeBounds(JNIEnv* env, jobject clazz, jlong objHandle, jobject jbounds) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
const SkRect& bounds = obj->getBounds();
GraphicsJNI::rect_to_jrectf(bounds, env, jbounds);
}
-
+
static void incReserve(JNIEnv* env, jobject clazz, jlong objHandle, jint extraPtCount) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->incReserve(extraPtCount);
}
-
+
static void moveTo__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->moveTo(x, y);
}
-
+
static void rMoveTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->rMoveTo(dx, dy);
}
-
+
static void lineTo__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->lineTo(x, y);
}
-
+
static void rLineTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->rLineTo(dx, dy);
}
-
+
static void quadTo__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->quadTo(x1, y1, x2, y2);
}
-
+
static void rQuadTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->rQuadTo(dx1, dy1, dx2, dy2);
}
-
+
static void cubicTo__FFFFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->cubicTo(x1, y1, x2, y2, x3, y3);
}
-
+
static void rCubicTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->rCubicTo(x1, y1, x2, y2, x3, y3);
}
-
- static void arcTo(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jfloat startAngle, jfloat sweepAngle, jboolean forceMoveTo) {
+
+ static void arcTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top,
+ jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle,
+ jboolean forceMoveTo) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
- SkRect oval_;
- GraphicsJNI::jrectf_to_rect(env, oval, &oval_);
- obj->arcTo(oval_, startAngle, sweepAngle, forceMoveTo);
+ SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
+ obj->arcTo(oval, startAngle, sweepAngle, forceMoveTo);
}
-
+
static void close(JNIEnv* env, jobject clazz, jlong objHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->close();
@@ -185,28 +186,26 @@
obj->addCircle(x, y, radius, dir);
}
- static void addArc(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jfloat startAngle, jfloat sweepAngle) {
- SkRect oval_;
+ static void addArc(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top,
+ jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle) {
+ SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
- GraphicsJNI::jrectf_to_rect(env, oval, &oval_);
- obj->addArc(oval_, startAngle, sweepAngle);
+ obj->addArc(oval, startAngle, sweepAngle);
}
- static void addRoundRectXY(JNIEnv* env, jobject clazz, jlong objHandle, jobject jrect,
- jfloat rx, jfloat ry, jint dirHandle) {
- SkRect rect;
+ static void addRoundRectXY(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top,
+ jfloat right, jfloat bottom, jfloat rx, jfloat ry, jint dirHandle) {
+ SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
- GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
obj->addRoundRect(rect, rx, ry, dir);
}
-
- static void addRoundRect8(JNIEnv* env, jobject, jlong objHandle, jobject jrect,
- jfloatArray array, jint dirHandle) {
- SkRect rect;
+
+ static void addRoundRect8(JNIEnv* env, jobject, jlong objHandle, jfloat left, jfloat top,
+ jfloat right, jfloat bottom, jfloatArray array, jint dirHandle) {
+ SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
- GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
AutoJavaFloatArray afa(env, array, 8);
#ifdef SK_SCALAR_IS_FLOAT
const float* src = afa.ptr();
@@ -215,32 +214,32 @@
#endif
obj->addRoundRect(rect, src, dir);
}
-
+
static void addPath__PathFF(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jfloat dx, jfloat dy) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
obj->addPath(*src, dx, dy);
}
-
+
static void addPath__Path(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
obj->addPath(*src);
}
-
+
static void addPath__PathMatrix(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jlong matrixHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
obj->addPath(*src, *matrix);
}
-
+
static void offset__FFPath(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy, jlong dstHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
obj->offset(dx, dy, dst);
}
-
+
static void offset__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->offset(dx, dy);
@@ -250,14 +249,14 @@
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->setLastPt(dx, dy);
}
-
+
static void transform__MatrixPath(JNIEnv* env, jobject clazz, jlong objHandle, jlong matrixHandle, jlong dstHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
obj->transform(*matrix, dst);
}
-
+
static void transform__Matrix(JNIEnv* env, jobject clazz, jlong objHandle, jlong matrixHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
@@ -487,14 +486,14 @@
{"native_rQuadTo","(JFFFF)V", (void*) SkPathGlue::rQuadTo},
{"native_cubicTo","(JFFFFFF)V", (void*) SkPathGlue::cubicTo__FFFFFF},
{"native_rCubicTo","(JFFFFFF)V", (void*) SkPathGlue::rCubicTo},
- {"native_arcTo","(JLandroid/graphics/RectF;FFZ)V", (void*) SkPathGlue::arcTo},
+ {"native_arcTo","(JFFFFFFZ)V", (void*) SkPathGlue::arcTo},
{"native_close","(J)V", (void*) SkPathGlue::close},
{"native_addRect","(JFFFFI)V", (void*) SkPathGlue::addRect},
{"native_addOval","(JFFFFI)V", (void*) SkPathGlue::addOval},
{"native_addCircle","(JFFFI)V", (void*) SkPathGlue::addCircle},
- {"native_addArc","(JLandroid/graphics/RectF;FF)V", (void*) SkPathGlue::addArc},
- {"native_addRoundRect","(JLandroid/graphics/RectF;FFI)V", (void*) SkPathGlue::addRoundRectXY},
- {"native_addRoundRect","(JLandroid/graphics/RectF;[FI)V", (void*) SkPathGlue::addRoundRect8},
+ {"native_addArc","(JFFFFFF)V", (void*) SkPathGlue::addArc},
+ {"native_addRoundRect","(JFFFFFFI)V", (void*) SkPathGlue::addRoundRectXY},
+ {"native_addRoundRect","(JFFFF[FI)V", (void*) SkPathGlue::addRoundRect8},
{"native_addPath","(JJFF)V", (void*) SkPathGlue::addPath__PathFF},
{"native_addPath","(JJ)V", (void*) SkPathGlue::addPath__Path},
{"native_addPath","(JJJ)V", (void*) SkPathGlue::addPath__PathMatrix},
diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp
index a8a3dae..0683f73 100644
--- a/core/jni/android/graphics/Picture.cpp
+++ b/core/jni/android/graphics/Picture.cpp
@@ -17,9 +17,9 @@
#include "jni.h"
#include "GraphicsJNI.h"
#include <android_runtime/AndroidRuntime.h>
+#include "AndroidPicture.h"
#include "SkCanvas.h"
-#include "SkPicture.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "CreateJavaOutputStreamAdaptor.h"
@@ -29,45 +29,41 @@
class SkPictureGlue {
public:
static jlong newPicture(JNIEnv* env, jobject, jlong srcHandle) {
- const SkPicture* src = reinterpret_cast<SkPicture*>(srcHandle);
- if (src) {
- return reinterpret_cast<jlong>(new SkPicture(*src));
- } else {
- return reinterpret_cast<jlong>(new SkPicture);
- }
+ const AndroidPicture* src = reinterpret_cast<AndroidPicture*>(srcHandle);
+ return reinterpret_cast<jlong>(new AndroidPicture(src));
}
static jlong deserialize(JNIEnv* env, jobject, jobject jstream,
jbyteArray jstorage) {
- SkPicture* picture = NULL;
+ AndroidPicture* picture = NULL;
SkStream* strm = CreateJavaInputStreamAdaptor(env, jstream, jstorage);
if (strm) {
- picture = SkPicture::CreateFromStream(strm);
+ picture = AndroidPicture::CreateFromStream(strm);
delete strm;
}
return reinterpret_cast<jlong>(picture);
}
static void killPicture(JNIEnv* env, jobject, jlong pictureHandle) {
- SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle);
+ AndroidPicture* picture = reinterpret_cast<AndroidPicture*>(pictureHandle);
SkASSERT(picture);
- picture->unref();
+ delete picture;
}
static void draw(JNIEnv* env, jobject, jlong canvasHandle,
jlong pictureHandle) {
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(canvasHandle);
- SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle);
+ AndroidPicture* picture = reinterpret_cast<AndroidPicture*>(pictureHandle);
SkASSERT(canvas);
SkASSERT(picture);
picture->draw(canvas);
}
static jboolean serialize(JNIEnv* env, jobject, jlong pictureHandle,
- jobject jstream, jbyteArray jstorage) {
- SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle);
+ jobject jstream, jbyteArray jstorage) {
+ AndroidPicture* picture = reinterpret_cast<AndroidPicture*>(pictureHandle);
SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
-
+
if (NULL != strm) {
picture->serialize(strm);
delete strm;
@@ -78,19 +74,21 @@
static jint getWidth(JNIEnv* env, jobject jpic) {
NPE_CHECK_RETURN_ZERO(env, jpic);
- int width = GraphicsJNI::getNativePicture(env, jpic)->width();
+ AndroidPicture* pict = GraphicsJNI::getNativePicture(env, jpic);
+ int width = pict->width();
return static_cast<jint>(width);
}
static jint getHeight(JNIEnv* env, jobject jpic) {
NPE_CHECK_RETURN_ZERO(env, jpic);
- int height = GraphicsJNI::getNativePicture(env, jpic)->height();
+ AndroidPicture* pict = GraphicsJNI::getNativePicture(env, jpic);
+ int height = pict->height();
return static_cast<jint>(height);
}
static jlong beginRecording(JNIEnv* env, jobject, jlong pictHandle,
- jint w, jint h) {
- SkPicture* pict = reinterpret_cast<SkPicture*>(pictHandle);
+ jint w, jint h) {
+ AndroidPicture* pict = reinterpret_cast<AndroidPicture*>(pictHandle);
// beginRecording does not ref its return value, it just returns it.
SkCanvas* canvas = pict->beginRecording(w, h);
// the java side will wrap this guy in a Canvas.java, which will call
@@ -101,7 +99,7 @@
}
static void endRecording(JNIEnv* env, jobject, jlong pictHandle) {
- SkPicture* pict = reinterpret_cast<SkPicture*>(pictHandle);
+ AndroidPicture* pict = reinterpret_cast<AndroidPicture*>(pictHandle);
pict->endRecording();
}
};
diff --git a/core/jni/android/graphics/TypefaceImpl.cpp b/core/jni/android/graphics/TypefaceImpl.cpp
index 27df7cf..1800d0c 100644
--- a/core/jni/android/graphics/TypefaceImpl.cpp
+++ b/core/jni/android/graphics/TypefaceImpl.cpp
@@ -173,7 +173,7 @@
} else {
const FontStyle defaultStyle;
FontFamily* firstFamily = reinterpret_cast<FontFamily*>(families[0]);
- MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle);
+ MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font;
SkTypeface* skTypeface = reinterpret_cast<MinikinFontSkia*>(mf)->GetSkTypeface();
// TODO: probably better to query more precise style from family, will be important
// when we open up API to access 100..900 weights
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index d54aaa8..3812c27 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -24,6 +24,7 @@
#include "SkCanvas.h"
#include "SkDocument.h"
#include "SkPicture.h"
+#include "SkPictureRecorder.h"
#include "SkStream.h"
#include "SkRect.h"
@@ -32,15 +33,22 @@
struct PageRecord {
PageRecord(int width, int height, const SkRect& contentRect)
- : mPicture(new SkPicture()), mWidth(width), mHeight(height) {
+ : mPictureRecorder(new SkPictureRecorder())
+ , mPicture(NULL)
+ , mWidth(width)
+ , mHeight(height) {
mContentRect = contentRect;
}
~PageRecord() {
- mPicture->unref();
+ delete mPictureRecorder;
+ if (NULL != mPicture) {
+ mPicture->unref();
+ }
}
- SkPicture* const mPicture;
+ SkPictureRecorder* mPictureRecorder;
+ SkPicture* mPicture;
const int mWidth;
const int mHeight;
SkRect mContentRect;
@@ -62,8 +70,8 @@
mPages.push_back(page);
mCurrentPage = page;
- SkCanvas* canvas = page->mPicture->beginRecording(
- contentRect.width(), contentRect.height(), 0);
+ SkCanvas* canvas = page->mPictureRecorder->beginRecording(
+ contentRect.width(), contentRect.height(), NULL, 0);
// We pass this canvas to Java where it is used to construct
// a Java Canvas object which dereferences the pointer when it
@@ -75,7 +83,11 @@
void finishPage() {
assert(mCurrentPage != NULL);
- mCurrentPage->mPicture->endRecording();
+ assert(mCurrentPage->mPictureRecorder != NULL);
+ assert(mCurrentPage->mPicture == NULL);
+ mCurrentPage->mPicture = mCurrentPage->mPictureRecorder->endRecording();
+ delete mCurrentPage->mPictureRecorder;
+ mCurrentPage->mPictureRecorder = NULL;
mCurrentPage = NULL;
}
@@ -89,7 +101,7 @@
canvas->clipRect(page->mContentRect);
canvas->translate(page->mContentRect.left(), page->mContentRect.top());
- canvas->drawPicture(*page->mPicture);
+ canvas->drawPicture(page->mPicture);
document->endPage();
}
@@ -97,11 +109,10 @@
}
void close() {
+ assert(NULL == mCurrentPage);
for (unsigned i = 0; i < mPages.size(); i++) {
delete mPages[i];
}
- delete mCurrentPage;
- mCurrentPage = NULL;
}
private:
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index ddcc396..c588942 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -52,7 +52,7 @@
jfieldID stringType;
jfieldID requiredPermission;
jfieldID maxDelay;
- jfieldID isWakeUpSensor;
+ jfieldID flags;
} gSensorOffsets;
@@ -81,7 +81,7 @@
sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission",
"Ljava/lang/String;");
sensorOffsets.maxDelay = _env->GetFieldID(sensorClass, "mMaxDelay", "I");
- sensorOffsets.isWakeUpSensor = _env->GetFieldID(sensorClass, "mWakeUpSensor", "Z");
+ sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags", "I");
}
static jint
@@ -117,7 +117,7 @@
env->SetObjectField(sensor, sensorOffsets.requiredPermission,
requiredPermission);
env->SetIntField(sensor, sensorOffsets.maxDelay, list->getMaxDelay());
- env->SetBooleanField(sensor, sensorOffsets.isWakeUpSensor, list->isWakeUpSensor());
+ env->SetIntField(sensor, sensorOffsets.flags, list->getFlags());
next++;
return size_t(next) < count ? next : 0;
}
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index bf47dd3..ee4c619 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -244,6 +244,12 @@
}
static jint
+android_media_AudioSystem_newAudioSessionId(JNIEnv *env, jobject thiz)
+{
+ return AudioSystem::newAudioSessionId();
+}
+
+static jint
android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
{
const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
@@ -1295,6 +1301,7 @@
{"isStreamActive", "(II)Z", (void *)android_media_AudioSystem_isStreamActive},
{"isStreamActiveRemotely","(II)Z", (void *)android_media_AudioSystem_isStreamActiveRemotely},
{"isSourceActive", "(I)Z", (void *)android_media_AudioSystem_isSourceActive},
+ {"newAudioSessionId", "()I", (void *)android_media_AudioSystem_newAudioSessionId},
{"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
{"getDeviceConnectionState", "(ILjava/lang/String;)I", (void *)android_media_AudioSystem_getDeviceConnectionState},
{"setPhoneState", "(I)I", (void *)android_media_AudioSystem_setPhoneState},
diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp
index f8a1fd9..ad36843c 100644
--- a/core/jni/android_server_FingerprintManager.cpp
+++ b/core/jni/android_server_FingerprintManager.cpp
@@ -20,30 +20,10 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
+#include <hardware/hardware.h>
+#include <hardware/fingerprint.h>
#include <utils/Log.h>
-namespace android {
-
-static struct {
- jclass clazz;
- jmethodID notify;
-} gFingerprintManagerClassInfo;
-
-static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
- return -1; // TODO
-}
-
-static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
- return -1; // TODO
-}
-
-// ----------------------------------------------------------------------------
-
-static const JNINativeMethod g_methods[] = {
- { "nativeEnroll", "(I)I", (void*)nativeEnroll },
- { "nativeRemove", "(I)I", (void*)nativeRemove },
-};
-
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
LOG_FATAL_IF(! var, "Unable to find class " className); \
@@ -61,13 +41,174 @@
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-int register_android_server_FingerprintManager(JNIEnv* env) {
- FIND_CLASS(gFingerprintManagerClassInfo.clazz,
- "android/service/fingerprint/FingerprintManager");
- GET_METHOD_ID(gFingerprintManagerClassInfo.notify, gFingerprintManagerClassInfo.clazz,
- "notify", "(III)V");
- return AndroidRuntime::registerNativeMethods(
- env, "com/android/service/fingerprint/FingerprintManager", g_methods, NELEM(g_methods));
+namespace android {
+
+static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(1, 0);
+
+static const char* FINGERPRINT_SERVICE = "com/android/server/fingerprint/FingerprintService";
+static struct {
+ jclass clazz;
+ jmethodID notify;
+ jobject callbackObject;
+} gFingerprintServiceClassInfo;
+
+static struct {
+ fingerprint_module_t const* module;
+ fingerprint_device_t *device;
+} gContext;
+
+// TODO: remove after driver update to use new HAL
+fingerprint_msg_type_t hackTilFpDriverUpdate(fingerprint_msg_type_t t) {
+ switch(static_cast<int>(t)) {
+ case 1: return FINGERPRINT_PROCESSED;
+ case 2: return FINGERPRINT_TEMPLATE_ENROLLING;
+ default: return t;
+ }
+}
+
+// Called by the HAL to notify us of fingerprint events
+static void hal_notify_callback(fingerprint_msg_t msg) {
+ uint32_t arg1 = 0;
+ uint32_t arg2 = 0;
+ uint32_t arg3 = 0; // TODO
+ msg.type = hackTilFpDriverUpdate(msg.type);
+ switch (msg.type) {
+ case FINGERPRINT_ERROR:
+ arg1 = msg.data.error;
+ break;
+ case FINGERPRINT_ACQUIRED:
+ arg1 = msg.data.acquired.acquired_info;
+ break;
+ case FINGERPRINT_PROCESSED:
+ arg1 = msg.data.processed.id;
+ break;
+ case FINGERPRINT_TEMPLATE_ENROLLING:
+ arg1 = msg.data.enroll.id;
+ arg2 = msg.data.enroll.samples_remaining;
+ arg3 = msg.data.enroll.data_collected_bmp;
+ break;
+ case FINGERPRINT_TEMPLATE_REMOVED:
+ arg1 = msg.data.removed.id;
+ break;
+ default:
+ ALOGE("fingerprint: invalid msg: %d", msg.type);
+ return;
+ }
+ //ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2);
+
+ // TODO: fix gross hack to attach JNI to calling thread
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ if (env == NULL) {
+ JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
+ JavaVM* vm = AndroidRuntime::getJavaVM();
+ int result = vm->AttachCurrentThread(&env, (void*) &args);
+ if (result != JNI_OK) {
+ ALOGE("Can't call JNI method: attach failed: %#x", result);
+ return;
+ }
+ }
+ env->CallVoidMethod(gFingerprintServiceClassInfo.callbackObject,
+ gFingerprintServiceClassInfo.notify, msg.type, arg1, arg2);
+}
+
+static void nativeInit(JNIEnv *env, jobject clazz, jobject callbackObj) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeInit()\n");
+ FIND_CLASS(gFingerprintServiceClassInfo.clazz, FINGERPRINT_SERVICE);
+ GET_METHOD_ID(gFingerprintServiceClassInfo.notify, gFingerprintServiceClassInfo.clazz,
+ "notify", "(III)V");
+ gFingerprintServiceClassInfo.callbackObject = env->NewGlobalRef(callbackObj);
+}
+
+static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll()\n");
+ int ret = gContext.device->enroll(gContext.device, timeout);
+ return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeEnrollCancel(JNIEnv* env, jobject clazz) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnrollCancel()\n");
+ int ret = gContext.device->enroll_cancel(gContext.device);
+ return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(%d)\n", fingerprintId);
+ int ret = gContext.device->remove(gContext.device, fingerprintId);
+ return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeOpenHal(JNIEnv* env, jobject clazz) {
+ ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n");
+ int err;
+ const hw_module_t *hw_module = NULL;
+ if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) {
+ ALOGE("Can't open fingerprint HW Module, error: %d", err);
+ return 0;
+ }
+ if (NULL == hw_module) {
+ ALOGE("No valid fingerprint module");
+ return 0;
+ }
+
+ gContext.module = reinterpret_cast<const fingerprint_module_t*>(hw_module);
+
+ if (gContext.module->common.methods->open == NULL) {
+ ALOGE("No valid open method");
+ return 0;
+ }
+
+ hw_device_t *device = NULL;
+
+ if (0 != (err = gContext.module->common.methods->open(hw_module, NULL, &device))) {
+ ALOGE("Can't open fingerprint methods, error: %d", err);
+ return 0;
+ }
+
+ if (kVersion != device->version) {
+ ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
+ // return 0; // FIXME
+ }
+
+ gContext.device = reinterpret_cast<fingerprint_device_t*>(device);
+ err = gContext.device->set_notify(gContext.device, hal_notify_callback);
+ if (err < 0) {
+ ALOGE("Failed in call to set_notify(), err=%d", err);
+ return 0;
+ }
+
+ // Sanity check - remove
+ if (gContext.device->notify != hal_notify_callback) {
+ ALOGE("NOTIFY not set properly: %p != %p", gContext.device->notify, hal_notify_callback);
+ }
+
+ ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized");
+ return reinterpret_cast<jlong>(gContext.device);
+}
+
+static jint nativeCloseHal(JNIEnv* env, jobject clazz) {
+ return -ENOSYS; // TODO
+}
+
+// ----------------------------------------------------------------------------
+
+// TODO: clean up void methods
+static const JNINativeMethod g_methods[] = {
+ { "nativeEnroll", "(I)I", (void*)nativeEnroll },
+ { "nativeEnrollCancel", "()I", (void*)nativeEnroll },
+ { "nativeRemove", "(I)I", (void*)nativeRemove },
+ { "nativeOpenHal", "()I", (void*)nativeOpenHal },
+ { "nativeCloseHal", "()I", (void*)nativeCloseHal },
+ { "nativeInit", "(Lcom/android/server/fingerprint/FingerprintService;)V", (void*)nativeInit }
+};
+
+int register_android_server_fingerprint_FingerprintService(JNIEnv* env) {
+ FIND_CLASS(gFingerprintServiceClassInfo.clazz, FINGERPRINT_SERVICE);
+ GET_METHOD_ID(gFingerprintServiceClassInfo.notify, gFingerprintServiceClassInfo.clazz, "notify",
+ "(III)V");
+ int result = AndroidRuntime::registerNativeMethods(
+ env, FINGERPRINT_SERVICE, g_methods, NELEM(g_methods));
+ ALOG(LOG_VERBOSE, LOG_TAG, "FingerprintManager JNI ready.\n");
+ return result;
}
} // namespace android
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 33fd346..4a6e117 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -599,13 +599,12 @@
uirenderer::Rect& bounds)
: layout(layout), renderer(renderer), x(x), y(y), paint(paint), glyphs(glyphs),
pos(pos), totalAdvance(totalAdvance), bounds(bounds) { }
- void operator()(SkTypeface* t, size_t start, size_t end) {
+ void operator()(size_t start, size_t end) {
for (size_t i = start; i < end; i++) {
glyphs[i] = layout.getGlyphId(i);
pos[2 * i] = layout.getX(i);
pos[2 * i + 1] = layout.getY(i);
}
- paint->setTypeface(t);
size_t glyphsCount = end - start;
int bytesCount = glyphsCount * sizeof(jchar);
renderer->drawText((const char*) (glyphs + start), bytesCount, glyphsCount,
@@ -635,23 +634,23 @@
float totalAdvance = layout->getAdvance();
RenderTextFunctor f(*layout, renderer, x, y, paint, glyphs, pos, totalAdvance, bounds);
- MinikinUtils::forFontRun(*layout, f);
+ MinikinUtils::forFontRun(*layout, paint, f);
delete[] glyphs;
delete[] pos;
}
#endif
static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
- jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) {
+ jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) {
#ifdef USE_MINIKIN
Layout layout;
- std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface);
+ std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
layout.doLayout(text, 0, count, count, css);
x += xOffsetForTextAlign(paint, layout.getAdvance());
renderTextLayout(renderer, &layout, x, y, paint);
#else
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
- text, 0, count, count, flags);
+ text, 0, count, count, bidiFlags);
if (value == NULL) {
return;
}
@@ -671,9 +670,9 @@
}
static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count,
- SkPath* path, jfloat hOffset, jfloat vOffset, int flags, SkPaint* paint) {
+ SkPath* path, jfloat hOffset, jfloat vOffset, int bidiFlags, SkPaint* paint) {
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
- text, 0, count, count, flags);
+ text, 0, count, count, bidiFlags);
if (value == NULL) {
return;
}
@@ -686,16 +685,16 @@
static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
jint start, jint count, jint contextCount, jfloat x, jfloat y,
- int flags, SkPaint* paint, TypefaceImpl* typeface) {
+ int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) {
#ifdef USE_MINIKIN
Layout layout;
- std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface);
+ std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface);
layout.doLayout(text, start, count, contextCount, css);
x += xOffsetForTextAlign(paint, layout.getAdvance());
renderTextLayout(renderer, &layout, x, y, paint);
#else
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
- text, start, count, contextCount, flags);
+ text, start, count, contextCount, bidiFlags);
if (value == NULL) {
return;
}
@@ -716,71 +715,72 @@
static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz,
jlong rendererPtr, jcharArray text, jint index, jint count,
- jfloat x, jfloat y, jint flags, jlong paintPtr, jlong typefacePtr) {
+ jfloat x, jfloat y, jint bidiFlags, jlong paintPtr, jlong typefacePtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
jchar* textArray = env->GetCharArrayElements(text, NULL);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
- renderText(renderer, textArray + index, count, x, y, flags, paint, typeface);
+ renderText(renderer, textArray + index, count, x, y, bidiFlags, paint, typeface);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz,
jlong rendererPtr, jstring text, jint start, jint end,
- jfloat x, jfloat y, jint flags, jlong paintPtr, jlong typefacePtr) {
+ jfloat x, jfloat y, jint bidiFlags, jlong paintPtr, jlong typefacePtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
const jchar* textArray = env->GetStringChars(text, NULL);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
- renderText(renderer, textArray + start, end - start, x, y, flags, paint, typeface);
+ renderText(renderer, textArray + start, end - start, x, y, bidiFlags, paint, typeface);
env->ReleaseStringChars(text, textArray);
}
static void android_view_GLES20Canvas_drawTextArrayOnPath(JNIEnv* env, jobject clazz,
jlong rendererPtr, jcharArray text, jint index, jint count,
- jlong pathPtr, jfloat hOffset, jfloat vOffset, jint flags, jlong paintPtr) {
+ jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
jchar* textArray = env->GetCharArrayElements(text, NULL);
SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
renderTextOnPath(renderer, textArray + index, count, path,
- hOffset, vOffset, flags, paint);
+ hOffset, vOffset, bidiFlags, paint);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
static void android_view_GLES20Canvas_drawTextOnPath(JNIEnv* env, jobject clazz,
jlong rendererPtr, jstring text, jint start, jint end,
- jlong pathPtr, jfloat hOffset, jfloat vOffset, jint flags, jlong paintPtr) {
+ jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
const jchar* textArray = env->GetStringChars(text, NULL);
SkPath* path = reinterpret_cast<SkPath*>(pathPtr);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
renderTextOnPath(renderer, textArray + start, end - start, path,
- hOffset, vOffset, flags, paint);
+ hOffset, vOffset, bidiFlags, paint);
env->ReleaseStringChars(text, textArray);
}
static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject clazz,
jlong rendererPtr, jcharArray text, jint index, jint count,
- jint contextIndex, jint contextCount, jfloat x, jfloat y, jint dirFlags,
+ jint contextIndex, jint contextCount, jfloat x, jfloat y, jboolean isRtl,
jlong paintPtr, jlong typefacePtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
jchar* textArray = env->GetCharArrayElements(text, NULL);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
+ int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
renderTextRun(renderer, textArray + contextIndex, index - contextIndex,
- count, contextCount, x, y, dirFlags, paint, typeface);
+ count, contextCount, x, y, bidiFlags, paint, typeface);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz,
jlong rendererPtr, jstring text, jint start, jint end,
- jint contextStart, int contextEnd, jfloat x, jfloat y, jint dirFlags,
+ jint contextStart, int contextEnd, jfloat x, jfloat y, jboolean isRtl,
jlong paintPtr, jlong typefacePtr) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
const jchar* textArray = env->GetStringChars(text, NULL);
@@ -789,15 +789,16 @@
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr);
+ int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
renderTextRun(renderer, textArray + contextStart, start - contextStart,
- count, contextCount, x, y, dirFlags, paint, typeface);
+ count, contextCount, x, y, bidiFlags, paint, typeface);
env->ReleaseStringChars(text, textArray);
}
static void renderPosText(OpenGLRenderer* renderer, const jchar* text, int count,
- const jfloat* positions, jint dirFlags, SkPaint* paint) {
+ const jfloat* positions, jint bidiFlags, SkPaint* paint) {
sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
- text, 0, count, count, dirFlags);
+ text, 0, count, count, bidiFlags);
if (value == NULL) {
return;
}
@@ -989,8 +990,8 @@
{ "nDrawTextOnPath", "(JLjava/lang/String;IIJFFIJ)V",
(void*) android_view_GLES20Canvas_drawTextOnPath },
- { "nDrawTextRun", "(J[CIIIIFFIJJ)V", (void*) android_view_GLES20Canvas_drawTextRunArray },
- { "nDrawTextRun", "(JLjava/lang/String;IIIIFFIJJ)V",
+ { "nDrawTextRun", "(J[CIIIIFFZJJ)V", (void*) android_view_GLES20Canvas_drawTextRunArray },
+ { "nDrawTextRun", "(JLjava/lang/String;IIIIFFZJJ)V",
(void*) android_view_GLES20Canvas_drawTextRun },
{ "nDrawPosText", "(J[CII[FJ)V", (void*) android_view_GLES20Canvas_drawPosTextArray },
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 64b077b..ace17ec 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -87,14 +87,6 @@
layer->updateTexImage();
}
-static void android_view_HardwareLayer_updateRenderLayer(JNIEnv* env, jobject clazz,
- jlong layerUpdaterPtr, jlong displayListPtr,
- jint left, jint top, jint right, jint bottom) {
- DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
- RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
- layer->setDisplayList(displayList, left, top, right, bottom);
-}
-
static jlong android_view_HardwareLayer_getLayer(JNIEnv* env, jobject clazz,
jlong layerUpdaterPtr) {
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
@@ -126,7 +118,6 @@
{ "nSetSurfaceTexture", "(JLandroid/graphics/SurfaceTexture;Z)V",
(void*) android_view_HardwareLayer_setSurfaceTexture },
{ "nUpdateSurfaceTexture", "(J)V", (void*) android_view_HardwareLayer_updateSurfaceTexture },
- { "nUpdateRenderLayer", "(JJIIII)V", (void*) android_view_HardwareLayer_updateRenderLayer },
{ "nGetLayer", "(J)J", (void*) android_view_HardwareLayer_getLayer },
{ "nGetTexName", "(J)I", (void*) android_view_HardwareLayer_getTexName },
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index e5f79f2..3ffde2d 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -87,9 +87,16 @@
// RenderProperties - setters
// ----------------------------------------------------------------------------
-static jboolean android_view_RenderNode_setCaching(JNIEnv* env,
- jobject clazz, jlong renderNodePtr, jboolean caching) {
- return SET_AND_DIRTY(setCaching, caching, RenderNode::GENERIC);
+static jboolean android_view_RenderNode_setLayerType(JNIEnv* env,
+ jobject clazz, jlong renderNodePtr, jint jlayerType) {
+ LayerType layerType = static_cast<LayerType>(jlayerType);
+ return SET_AND_DIRTY(mutateLayerProperties().setType, layerType, RenderNode::GENERIC);
+}
+
+static jboolean android_view_RenderNode_setLayerPaint(JNIEnv* env,
+ jobject clazz, jlong renderNodePtr, jlong paintPtr) {
+ SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
+ return SET_AND_DIRTY(mutateLayerProperties().setFromPaint, paint, RenderNode::GENERIC);
}
static jboolean android_view_RenderNode_setStaticMatrix(JNIEnv* env,
@@ -275,13 +282,6 @@
return SET_AND_DIRTY(offsetTopBottom, offset, RenderNode::Y);
}
-static void android_view_RenderNode_setScrollPosition(JNIEnv* env,
- jobject clazz, jlong renderNodePtr, jint scrollX, jint scrollY) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- SET_AND_DIRTY(setScrollX, scrollX, RenderNode::GENERIC);
- SET_AND_DIRTY(setScrollY, scrollY, RenderNode::GENERIC);
-}
-
// ----------------------------------------------------------------------------
// RenderProperties - getters
// ----------------------------------------------------------------------------
@@ -482,7 +482,8 @@
{ "nOutput", "(J)V", (void*) android_view_RenderNode_output },
{ "nGetDebugSize", "(J)I", (void*) android_view_RenderNode_getDebugSize },
- { "nSetCaching", "(JZ)Z", (void*) android_view_RenderNode_setCaching },
+ { "nSetLayerType", "(JI)Z", (void*) android_view_RenderNode_setLayerType },
+ { "nSetLayerPaint", "(JJ)Z", (void*) android_view_RenderNode_setLayerPaint },
{ "nSetStaticMatrix", "(JJ)Z", (void*) android_view_RenderNode_setStaticMatrix },
{ "nSetAnimationMatrix", "(JJ)Z", (void*) android_view_RenderNode_setAnimationMatrix },
{ "nSetClipToBounds", "(JZ)Z", (void*) android_view_RenderNode_setClipToBounds },
@@ -517,7 +518,6 @@
{ "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom },
{ "nOffsetLeftAndRight", "(JF)Z", (void*) android_view_RenderNode_offsetLeftAndRight },
{ "nOffsetTopAndBottom", "(JF)Z", (void*) android_view_RenderNode_offsetTopAndBottom },
- { "nSetScrollPosition", "(JII)V", (void*) android_view_RenderNode_setScrollPosition },
{ "nHasOverlappingRendering", "(J)Z", (void*) android_view_RenderNode_hasOverlappingRendering },
{ "nGetClipToOutline", "(J)Z", (void*) android_view_RenderNode_getClipToOutline },
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 11f87cc..3d14aaf 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -95,6 +95,7 @@
env->GetLongField(surfaceObj, gSurfaceClassInfo.mNativeObject));
env->MonitorExit(lock);
}
+ env->DeleteLocalRef(lock);
return sur;
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 4594cc3..c0d5221 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -42,6 +42,8 @@
#include <ScopedUtfChars.h>
+#include "SkTemplates.h"
+
// ----------------------------------------------------------------------------
namespace android {
@@ -125,7 +127,7 @@
int bottom = env->GetIntField(sourceCropObj, gRectClassInfo.bottom);
Rect sourceCrop(left, top, right, bottom);
- ScreenshotClient* screenshot = new ScreenshotClient();
+ SkAutoTDelete<ScreenshotClient> screenshot(new ScreenshotClient());
status_t res;
if (width > 0 && height > 0) {
if (allLayers) {
@@ -139,7 +141,6 @@
res = screenshot->update(displayToken, sourceCrop, useIdentityTransform);
}
if (res != NO_ERROR) {
- delete screenshot;
return NULL;
}
@@ -164,7 +165,6 @@
break;
}
default: {
- delete screenshot;
return NULL;
}
}
@@ -178,7 +178,7 @@
// takes ownership of ScreenshotClient
SkMallocPixelRef* pixels = SkMallocPixelRef::NewWithProc(screenshotInfo,
(size_t) rowBytes, NULL, (void*) screenshot->getPixels(), &DeleteScreenshot,
- (void*) screenshot);
+ (void*) (screenshot.detach()));
pixels->setImmutable();
bitmap->setPixelRef(pixels)->unref();
bitmap->lockPixels();
@@ -412,20 +412,12 @@
return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}
-static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
+static void nativeSetDisplayPowerMode(JNIEnv* env, jclass clazz, jobject tokenObj, jint mode) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
- ALOGD_IF_SLOW(100, "Excessive delay in blankDisplay() while turning screen off");
- SurfaceComposerClient::blankDisplay(token);
-}
-
-static void nativeUnblankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
- sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
- if (token == NULL) return;
-
- ALOGD_IF_SLOW(100, "Excessive delay in unblankDisplay() while turning screen on");
- SurfaceComposerClient::unblankDisplay(token);
+ ALOGD_IF_SLOW(100, "Excessive delay in setPowerMode()");
+ SurfaceComposerClient::setDisplayPowerMode(token, mode);
}
static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) {
@@ -628,10 +620,6 @@
(void*)nativeGetActiveConfig },
{"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z",
(void*)nativeSetActiveConfig },
- {"nativeBlankDisplay", "(Landroid/os/IBinder;)V",
- (void*)nativeBlankDisplay },
- {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
- (void*)nativeUnblankDisplay },
{"nativeClearContentFrameStats", "(J)Z",
(void*)nativeClearContentFrameStats },
{"nativeGetContentFrameStats", "(JLandroid/view/WindowContentFrameStats;)Z",
@@ -640,6 +628,8 @@
(void*)nativeClearAnimationFrameStats },
{"nativeGetAnimationFrameStats", "(Landroid/view/WindowAnimationFrameStats;)Z",
(void*)nativeGetAnimationFrameStats },
+ {"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V",
+ (void*)nativeSetDisplayPowerMode },
};
int register_android_view_SurfaceControl(JNIEnv* env)
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index e55e4ea..226b764 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -327,6 +327,7 @@
// Exception: If we find the gdbserver binary, return it.
if (!strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) {
+ mLastSlash = lastSlash;
break;
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index c58bf04..0cdddba 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -14,46 +14,40 @@
* limitations under the License.
*/
-#include "android_runtime/AndroidRuntime.h"
+#define LOG_TAG "Zygote"
// sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
#include <sys/mount.h>
#include <linux/fs.h>
#include <grp.h>
+#include <fcntl.h>
#include <paths.h>
#include <signal.h>
#include <stdlib.h>
-#include <sys/resource.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
#include <unistd.h>
-#include <fcntl.h>
+#include <sys/capability.h>
+#include <sys/personality.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
-#include "cutils/fs.h"
-#include "cutils/multiuser.h"
-#include "cutils/sched_policy.h"
-#include "utils/String8.h"
+
+#include <cutils/fs.h>
+#include <cutils/multiuser.h>
+#include <cutils/sched_policy.h>
+#include <utils/String8.h>
+#include <selinux/android.h>
+
+#include "android_runtime/AndroidRuntime.h"
#include "JNIHelp.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
#include "ScopedUtfChars.h"
-#if defined(HAVE_PRCTL)
-#include <sys/prctl.h>
-#endif
-
-#include <selinux/android.h>
-
-#if defined(__linux__)
-#include <sys/personality.h>
-#include <sys/utsname.h>
-#if defined(HAVE_ANDROID_OS)
-#include <sys/capability.h>
-#endif
-#endif
-
namespace {
using android::String8;
@@ -97,11 +91,9 @@
if (WTERMSIG(status) != SIGKILL) {
ALOGI("Process %d exited due to signal (%d)", pid, WTERMSIG(status));
}
-#ifdef WCOREDUMP
if (WCOREDUMP(status)) {
ALOGI("Process %d dumped core.", pid);
}
-#endif /* ifdef WCOREDUMP */
}
// If the just-crashed process is the system_server, bring down zygote
@@ -199,8 +191,6 @@
}
}
-#if defined(HAVE_ANDROID_OS)
-
// The debug malloc library needs to know whether it's the zygote or a child.
extern "C" int gMallocLeakZygoteChild;
@@ -254,17 +244,6 @@
}
}
-#else
-
-static int gMallocLeakZygoteChild = 0;
-
-static void EnableKeepCapabilities(JNIEnv*) {}
-static void DropCapabilitiesBoundingSet(JNIEnv*) {}
-static void SetCapabilities(JNIEnv*, int64_t, int64_t) {}
-static void SetSchedulerPolicy(JNIEnv*) {}
-
-#endif
-
// Create a private mount namespace and bind mount appropriate emulated
// storage for the given user.
static bool MountEmulatedStorage(uid_t uid, jint mount_mode) {
@@ -337,7 +316,6 @@
return true;
}
-#if defined(__linux__)
static bool NeedsNoRandomizeWorkaround() {
#if !defined(__arm__)
return false;
@@ -357,7 +335,6 @@
return (major < 3) || ((major == 3) && (minor < 4));
#endif
}
-#endif
// Utility to close down the Zygote socket file descriptors while
// the child is still running as root with Zygote's privileges. Each
@@ -474,7 +451,6 @@
RuntimeAbort(env);
}
-#if defined(__linux__)
if (NeedsNoRandomizeWorkaround()) {
// Work around ARM kernel ASLR lossage (http://b/5817320).
int old_personality = personality(0xffffffff);
@@ -483,58 +459,49 @@
ALOGW("personality(%d) failed", new_personality);
}
}
-#endif
SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
SetSchedulerPolicy(env);
-#if defined(HAVE_ANDROID_OS)
- { // NOLINT(whitespace/braces)
- const char* se_info_c_str = NULL;
- ScopedUtfChars* se_info = NULL;
- if (java_se_info != NULL) {
- se_info = new ScopedUtfChars(env, java_se_info);
- se_info_c_str = se_info->c_str();
- if (se_info_c_str == NULL) {
- ALOGE("se_info_c_str == NULL");
- RuntimeAbort(env);
- }
- }
- const char* se_name_c_str = NULL;
- ScopedUtfChars* se_name = NULL;
- if (java_se_name != NULL) {
- se_name = new ScopedUtfChars(env, java_se_name);
- se_name_c_str = se_name->c_str();
- if (se_name_c_str == NULL) {
- ALOGE("se_name_c_str == NULL");
- RuntimeAbort(env);
- }
- }
- rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
- if (rc == -1) {
- ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
- is_system_server, se_info_c_str, se_name_c_str);
- RuntimeAbort(env);
- }
-
- // Make it easier to debug audit logs by setting the main thread's name to the
- // nice name rather than "app_process".
- if (se_info_c_str == NULL && is_system_server) {
- se_name_c_str = "system_server";
- }
- if (se_info_c_str != NULL) {
- SetThreadName(se_name_c_str);
- }
-
- delete se_info;
- delete se_name;
+ const char* se_info_c_str = NULL;
+ ScopedUtfChars* se_info = NULL;
+ if (java_se_info != NULL) {
+ se_info = new ScopedUtfChars(env, java_se_info);
+ se_info_c_str = se_info->c_str();
+ if (se_info_c_str == NULL) {
+ ALOGE("se_info_c_str == NULL");
+ RuntimeAbort(env);
+ }
}
-#else
- UNUSED(is_system_server);
- UNUSED(java_se_info);
- UNUSED(java_se_name);
-#endif
+ const char* se_name_c_str = NULL;
+ ScopedUtfChars* se_name = NULL;
+ if (java_se_name != NULL) {
+ se_name = new ScopedUtfChars(env, java_se_name);
+ se_name_c_str = se_name->c_str();
+ if (se_name_c_str == NULL) {
+ ALOGE("se_name_c_str == NULL");
+ RuntimeAbort(env);
+ }
+ }
+ rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
+ if (rc == -1) {
+ ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
+ is_system_server, se_info_c_str, se_name_c_str);
+ RuntimeAbort(env);
+ }
+
+ // Make it easier to debug audit logs by setting the main thread's name to the
+ // nice name rather than "app_process".
+ if (se_info_c_str == NULL && is_system_server) {
+ se_name_c_str = "system_server";
+ }
+ if (se_info_c_str != NULL) {
+ SetThreadName(se_name_c_str);
+ }
+
+ delete se_info;
+ delete se_name;
UnsetSigChldHandler();
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e4cbf5f..c08c5e2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -123,10 +123,30 @@
<protected-broadcast
android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
<protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.AG_EVENT" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.RESULT" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
+ <protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
<protected-broadcast
+ android:name="android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED" />
@@ -301,7 +321,7 @@
android:label="@string/permlab_sendSms"
android:description="@string/permdesc_sendSms" />
- <!-- Allows an application (Phone) to send a request to other applications
+ <!-- @SystemApi Allows an application (Phone) to send a request to other applications
to handle the respond-via-message action during incoming calls.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE"
@@ -326,7 +346,7 @@
android:label="@string/permlab_receiveMms"
android:description="@string/permdesc_receiveMms" />
- <!-- Allows an application to receive emergency cell broadcast messages,
+ <!-- @SystemApi Allows an application to receive emergency cell broadcast messages,
to record or display them to the user.
<p>Not for use by third-party applications.
@hide Pending API council approval -->
@@ -406,10 +426,9 @@
android:label="@string/permlab_writeContacts"
android:description="@string/permdesc_writeContacts" />
- <!-- Allows an application to execute contacts directory search.
+ <!-- @SystemApi @hide Allows an application to execute contacts directory search.
This should only be used by ContactsProvider.
<p>Not for use by third-party applications. -->
- <!-- @hide -->
<permission android:name="android.permission.BIND_DIRECTORY_SEARCH"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
android:protectionLevel="signature|system" />
@@ -694,20 +713,20 @@
android:label="@string/permlab_accessLocationExtraCommands"
android:description="@string/permdesc_accessLocationExtraCommands" />
- <!-- Allows an application to install a location provider into the Location Manager.
+ <!-- @SystemApi Allows an application to install a location provider into the Location Manager.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.INSTALL_LOCATION_PROVIDER"
android:protectionLevel="signature|system"
android:label="@string/permlab_installLocationProvider"
android:description="@string/permdesc_installLocationProvider" />
- <!-- Allows HDMI-CEC service to access device and configuration files.
- @hide This should only be used by HDMI-CEC service.
+ <!-- @SystemApi @hide Allows HDMI-CEC service to access device and configuration files.
+ This should only be used by HDMI-CEC service.
-->
<permission android:name="android.permission.HDMI_CEC"
android:protectionLevel="signatureOrSystem" />
- <!-- Allows an application to use location features in hardware,
+ <!-- @SystemApi Allows an application to use location features in hardware,
such as the geofencing api.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.LOCATION_HARDWARE"
@@ -805,7 +824,7 @@
android:description="@string/permdesc_bluetoothAdmin"
android:label="@string/permlab_bluetoothAdmin" />
- <!-- Allows applications to pair bluetooth devices without user interaction.
+ <!-- @SystemApi Allows applications to pair bluetooth devices without user interaction.
This is not available to third party applications. -->
<permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
android:permissionGroup="android.permission-group.BLUETOOTH_NETWORK"
@@ -827,18 +846,18 @@
android:description="@string/permdesc_nfc"
android:label="@string/permlab_nfc" />
- <!-- Allows an internal user to use privileged ConnectivityManager APIs.
+ <!-- @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
@hide -->
<permission android:name="android.permission.CONNECTIVITY_INTERNAL"
android:permissionGroup="android.permission-group.NETWORK"
android:protectionLevel="signature|system" />
- <!-- @hide -->
+ <!-- @SystemApi @hide -->
<permission android:name="android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"
android:permissionGroup="android.permission-group.NETWORK"
android:protectionLevel="signature|system" />
- <!-- Allows access to the loop radio (Android@Home mesh network) device.
+ <!-- @SystemApi Allows access to the loop radio (Android@Home mesh network) device.
@hide -->
<permission android:name="android.permission.LOOP_RADIO"
android:permissionGroup="android.permission-group.NETWORK"
@@ -887,7 +906,7 @@
android:label="@string/permlab_manageAccounts"
android:description="@string/permdesc_manageAccounts" />
- <!-- Allows applications to call into AccountAuthenticators.
+ <!-- @SystemApi Allows applications to call into AccountAuthenticators.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCOUNT_MANAGER"
android:permissionGroup="android.permission-group.ACCOUNTS"
@@ -978,7 +997,7 @@
android:description="@string/permgroupdesc_hardwareControls"
android:priority="260"/>
- <!-- Allows an application to manage preferences and permissions for USB devices
+ <!-- @SystemApi Allows an application to manage preferences and permissions for USB devices
@hide -->
<permission android:name="android.permission.MANAGE_USB"
android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
@@ -986,7 +1005,7 @@
android:label="@string/permlab_manageUsb"
android:description="@string/permdesc_manageUsb" />
- <!-- Allows an application to access the MTP USB kernel driver.
+ <!-- @SystemApi Allows an application to access the MTP USB kernel driver.
For use only by the device side MTP implementation.
@hide -->
<permission android:name="android.permission.ACCESS_MTP"
@@ -1022,7 +1041,7 @@
android:description="@string/permdesc_sim_communication"
android:protectionLevel="dangerous" />
- <!-- Allows TvInputService to access underlying TV input hardware such as
+ <!-- @SystemApi Allows TvInputService to access underlying TV input hardware such as
built-in tuners and HDMI-in's.
@hide This should only be used by OEM's TvInputService's.
-->
@@ -1079,7 +1098,7 @@
android:label="@string/permlab_camera"
android:description="@string/permdesc_camera" />
- <!-- Allows disabling the transmit-indicator LED that is normally on when
+ <!-- @SystemApi Allows disabling the transmit-indicator LED that is normally on when
a camera is in use by an application.
@hide -->
<permission android:name="android.permission.CAMERA_DISABLE_TRANSMIT_LED"
@@ -1112,7 +1131,7 @@
android:label="@string/permlab_processOutgoingCalls"
android:description="@string/permdesc_processOutgoingCalls" />
- <!-- Allows modification of the telephony state - power on, mmi, etc.
+ <!-- @SystemApi Allows modification of the telephony state - power on, mmi, etc.
Does not include placing calls.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.MODIFY_PHONE_STATE"
@@ -1144,7 +1163,7 @@
android:label="@string/permlab_readPrecisePhoneState"
android:description="@string/permdesc_readPrecisePhoneState" />
- <!-- Allows read access to privileged phone state.
+ <!-- @SystemApi Allows read access to privileged phone state.
@hide Used internally. -->
<permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
android:permissionGroup="android.permission-group.PHONE_CALLS"
@@ -1167,7 +1186,7 @@
android:description="@string/permdesc_use_sip"
android:label="@string/permlab_use_sip" />
- <!-- Allows an application to request CallHandlerService implementations.
+ <!-- @SystemApi Allows an application to request CallHandlerService implementations.
@hide -->
<permission android:name="android.permission.BIND_CALL_SERVICE"
android:permissionGroup="android.permission-group.PHONE_CALLS"
@@ -1233,7 +1252,7 @@
android:description="@string/permdesc_sdcardWrite"
android:protectionLevel="dangerous" />
- <!-- Allows an application to write to internal media storage
+ <!-- @SystemApi Allows an application to write to internal media storage
@hide -->
<permission android:name="android.permission.WRITE_MEDIA_STORAGE"
android:permissionGroup="android.permission-group.STORAGE"
@@ -1283,14 +1302,15 @@
android:description="@string/permgroupdesc_appInfo"
android:priority="220" />
- <!-- Allows an application to get information about the currently
+ <!-- @SystemApi Allows an application to get information about the currently
or recently running tasks. -->
<permission android:name="android.permission.GET_TASKS"
android:permissionGroup="android.permission-group.APP_INFO"
android:protectionLevel="signature|system"
android:label="@string/permlab_getTasks"
android:description="@string/permdesc_getTasks" />
- <!-- @hide Allows an application to call APIs that allow it to do interactions
+
+ <!-- @SystemApi @hide Allows an application to call APIs that allow it to do interactions
across the users on the device, using singleton services and
user-targeted broadcasts. This permission is not available to
third party applications. -->
@@ -1309,7 +1329,7 @@
android:label="@string/permlab_interactAcrossUsersFull"
android:description="@string/permdesc_interactAcrossUsersFull" />
- <!-- @hide Allows an application to call APIs that allow it to query and manage
+ <!-- @SystemApi @hide Allows an application to call APIs that allow it to query and manage
users on the device. This permission is not available to
third party applications. -->
<permission android:name="android.permission.MANAGE_USERS"
@@ -1341,7 +1361,7 @@
android:label="@string/permlab_removeTasks"
android:description="@string/permdesc_removeTasks" />
- <!-- @hide Allows an application to create/manage/remove stacks -->
+ <!-- @SystemApi @hide Allows an application to create/manage/remove stacks -->
<permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"
android:permissionGroup="android.permission-group.APP_INFO"
android:protectionLevel="signature|system"
@@ -1435,7 +1455,7 @@
android:description="@string/permgroupdesc_systemClock"
android:priority="140" />
- <!-- Allows applications to set the system time.
+ <!-- @SystemApi Allows applications to set the system time.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_TIME"
android:protectionLevel="signature|system"
@@ -1541,7 +1561,7 @@
android:description="@string/permgroupdesc_systemTools"
android:priority="100" />
- <!-- @hide Change the screen compatibility mode of applications -->
+ <!-- @SystemApi @hide Change the screen compatibility mode of applications -->
<permission android:name="android.permission.SET_SCREEN_COMPATIBILITY"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signature"
@@ -1555,7 +1575,7 @@
android:description="@string/permdesc_sdcardAccessAll"
android:protectionLevel="signature" />
- <!-- Allows an application to modify the current configuration, such
+ <!-- @SystemApi Allows an application to modify the current configuration, such
as locale. -->
<permission android:name="android.permission.CHANGE_CONFIGURATION"
android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
@@ -1570,14 +1590,14 @@
android:label="@string/permlab_writeSettings"
android:description="@string/permdesc_writeSettings" />
- <!-- Allows an application to modify the Google service map.
+ <!-- @SystemApi Allows an application to modify the Google service map.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WRITE_GSERVICES"
android:protectionLevel="signature|system"
android:label="@string/permlab_writeGservices"
android:description="@string/permdesc_writeGservices" />
- <!-- Allows an application to call
+ <!-- @SystemApi Allows an application to call
{@link android.app.ActivityManager#forceStopPackage}.
@hide -->
<permission android:name="android.permission.FORCE_STOP_PACKAGES"
@@ -1586,7 +1606,7 @@
android:label="@string/permlab_forceStopPackages"
android:description="@string/permdesc_forceStopPackages" />
- <!-- @hide Allows an application to retrieve the content of the active window
+ <!-- @SystemApi @hide Allows an application to retrieve the content of the active window
An active window is the window that has fired an accessibility event. -->
<permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
@@ -1594,7 +1614,7 @@
android:label="@string/permlab_retrieve_window_content"
android:description="@string/permdesc_retrieve_window_content" />
- <!-- Modify the global animation scaling factor.
+ <!-- @SystemApi Modify the global animation scaling factor.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_ANIMATION_SCALE"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -1653,7 +1673,7 @@
android:label="@string/permlab_broadcastSticky"
android:description="@string/permdesc_broadcastSticky" />
- <!-- Allows mounting and unmounting file systems for removable storage.
+ <!-- @SystemApi Allows mounting and unmounting file systems for removable storage.
<p>Not for use by third-party applications.-->
<permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -1661,7 +1681,7 @@
android:label="@string/permlab_mount_unmount_filesystems"
android:description="@string/permdesc_mount_unmount_filesystems" />
- <!-- Allows formatting file systems for removable storage.
+ <!-- @SystemApi Allows formatting file systems for removable storage.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -1709,7 +1729,7 @@
android:label="@string/permlab_asec_rename"
android:description="@string/permdesc_asec_rename" />
- <!-- Allows applications to write the apn settings.
+ <!-- @SystemApi Allows applications to write the apn settings.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WRITE_APN_SETTINGS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -1745,14 +1765,14 @@
android:label="@string/permlab_clearAppCache"
android:description="@string/permdesc_clearAppCache" />
- <!-- Allows an application to use any media decoder when decoding for playback
+ <!-- @SystemApi Allows an application to use any media decoder when decoding for playback
@hide -->
<permission android:name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"
android:protectionLevel="signature|system"
android:label="@string/permlab_anyCodecForPlayback"
android:description="@string/permdesc_anyCodecForPlayback" />
- <!-- Allows an application to install and/or uninstall CA certificates on
+ <!-- @SystemApi Allows an application to install and/or uninstall CA certificates on
behalf of the user.
@hide -->
<permission android:name="android.permission.MANAGE_CA_CERTIFICATES"
@@ -1760,7 +1780,7 @@
android:label="@string/permlab_manageCaCertificates"
android:description="@string/permdesc_manageCaCertificates" />
- <!-- Allows an application to do certain operations needed for
+ <!-- @SystemApi Allows an application to do certain operations needed for
interacting with the recovery (system update) system. -->
<permission android:name="android.permission.RECOVERY"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -1768,12 +1788,13 @@
android:label="@string/permlab_recovery"
android:description="@string/permdesc_recovery" />
- <!-- Allows the system to bind to an application's idle services
+ <!-- Allows the system to bind to an application's task services
@hide -->
- <permission android:name="android.permission.BIND_IDLE_SERVICE"
+ <permission android:name="android.permission.BIND_JOB_SERVICE"
android:protectionLevel="signature"
- android:label="@string/permlab_bindIdleService"
- android:description="@string/permdesc_bindIdleService" />
+ android:label="@string/permlab_bindJobService"
+ android:description="@string/permdesc_bindJobService" />
+ <uses-permission android:name="android.permission.BIND_JOB_SERVICE"/>
<!-- ========================================= -->
<!-- Permissions for special development tools -->
@@ -1789,7 +1810,7 @@
android:description="@string/permgroupdesc_developmentTools"
android:priority="310" />
- <!-- Allows an application to read or write the secure system settings.
+ <!-- @SystemApi Allows an application to read or write the secure system settings.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WRITE_SECURE_SETTINGS"
android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
@@ -1797,7 +1818,7 @@
android:label="@string/permlab_writeSecureSettings"
android:description="@string/permdesc_writeSecureSettings" />
- <!-- Allows an application to retrieve state dump information from system services.
+ <!-- @SystemApi Allows an application to retrieve state dump information from system services.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DUMP"
android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
@@ -1805,7 +1826,7 @@
android:label="@string/permlab_dump"
android:description="@string/permdesc_dump" />
- <!-- Allows an application to read the low-level system log files.
+ <!-- @SystemApi Allows an application to read the low-level system log files.
<p>Not for use by third-party applications, because
Log entries can contain the user's private information. -->
<permission android:name="android.permission.READ_LOGS"
@@ -1814,7 +1835,7 @@
android:label="@string/permlab_readLogs"
android:description="@string/permdesc_readLogs" />
- <!-- Configure an application for debugging.
+ <!-- @SystemApi Configure an application for debugging.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_DEBUG_APP"
android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
@@ -1822,7 +1843,7 @@
android:label="@string/permlab_setDebugApp"
android:description="@string/permdesc_setDebugApp" />
- <!-- Allows an application to set the maximum number of (not needed)
+ <!-- @SystemApi Allows an application to set the maximum number of (not needed)
application processes that can be running.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_PROCESS_LIMIT"
@@ -1831,7 +1852,7 @@
android:label="@string/permlab_setProcessLimit"
android:description="@string/permdesc_setProcessLimit" />
- <!-- Allows an application to control whether activities are immediately
+ <!-- @SystemApi Allows an application to control whether activities are immediately
finished when put in the background.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_ALWAYS_FINISH"
@@ -1840,7 +1861,7 @@
android:label="@string/permlab_setAlwaysFinish"
android:description="@string/permdesc_setAlwaysFinish" />
- <!-- Allow an application to request that a signal be sent to all persistent processes.
+ <!-- @SystemApi Allow an application to request that a signal be sent to all persistent processes.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES"
android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
@@ -1853,7 +1874,7 @@
<!-- ==================================== -->
<eat-comment />
- <!-- Allows applications to RW to diagnostic resources.
+ <!-- @SystemApi Allows applications to RW to diagnostic resources.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DIAGNOSTIC"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -1861,7 +1882,7 @@
android:description="@string/permdesc_diagnostic"
android:label="@string/permlab_diagnostic" />
- <!-- Allows an application to open, close, or disable the status bar
+ <!-- @SystemApi Allows an application to open, close, or disable the status bar
and its icons.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.STATUS_BAR"
@@ -1884,21 +1905,21 @@
android:description="@string/permdesc_forceBack"
android:protectionLevel="signature" />
- <!-- Allows an application to update device statistics.
+ <!-- @SystemApi Allows an application to update device statistics.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.UPDATE_DEVICE_STATS"
android:label="@string/permlab_updateBatteryStats"
android:description="@string/permdesc_updateBatteryStats"
android:protectionLevel="signature|system" />
- <!-- @hide Allows an application to collect battery statistics -->
+ <!-- @SystemApi @hide Allows an application to collect battery statistics -->
<permission android:name="android.permission.GET_APP_OPS_STATS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:label="@string/permlab_getAppOpsStats"
android:description="@string/permdesc_getAppOpsStats"
android:protectionLevel="signature|system|development" />
- <!-- Allows an application to update application operation statistics. Not for
+ <!-- @SystemApi Allows an application to update application operation statistics. Not for
use by third party apps. @hide -->
<permission android:name="android.permission.UPDATE_APP_OPS_STATS"
android:label="@string/permlab_updateAppOpsStats"
@@ -1971,7 +1992,7 @@
android:description="@string/permdesc_runSetActivityWatcher"
android:protectionLevel="signature" />
- <!-- Allows an application to call the activity manager shutdown() API
+ <!-- @SystemApi Allows an application to call the activity manager shutdown() API
to put the higher-level system there into a shutdown state.
@hide -->
<permission android:name="android.permission.SHUTDOWN"
@@ -1979,7 +2000,7 @@
android:description="@string/permdesc_shutdown"
android:protectionLevel="signature|system" />
- <!-- Allows an application to tell the activity manager to temporarily
+ <!-- @SystemApi Allows an application to tell the activity manager to temporarily
stop application switches, putting it into a special mode that
prevents applications from immediately switching away from some
critical UI such as the home screen.
@@ -2070,6 +2091,14 @@
android:description="@string/permdesc_bindVoiceInteraction"
android:protectionLevel="signature" />
+ <!-- Must be required by hotword enrollment application,
+ to ensure that only the system can interact with it.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES"
+ android:label="@string/permlab_manageVoiceKeyphrases"
+ android:description="@string/permdesc_manageVoiceKeyphrases"
+ android:protectionLevel="signature|system" />
+
<!-- Must be required by a {@link com.android.media.remotedisplay.RemoteDisplayProvider},
to ensure that only the system can bind to it.
@hide -->
@@ -2100,7 +2129,7 @@
android:description="@string/permdesc_bindDeviceAdmin"
android:protectionLevel="signature" />
- <!-- Required to add or remove another application as a device admin.
+ <!-- @SystemApi Required to add or remove another application as a device admin.
<p>Not for use by third-party applications.
@hide -->
<permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
@@ -2139,7 +2168,7 @@
android:description="@string/permdesc_setKeyboardLayout"
android:protectionLevel="signature" />
- <!-- Allows an application to install packages.
+ <!-- @SystemApi Allows an application to install packages.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.INSTALL_PACKAGES"
android:label="@string/permlab_installPackages"
@@ -2153,28 +2182,28 @@
android:description="@string/permdesc_clearAppUserData"
android:protectionLevel="signature" />
- <!-- Allows an application to delete cache files.
+ <!-- @SystemApi Allows an application to delete cache files.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DELETE_CACHE_FILES"
android:label="@string/permlab_deleteCacheFiles"
android:description="@string/permdesc_deleteCacheFiles"
android:protectionLevel="signature|system" />
- <!-- Allows an application to delete packages.
+ <!-- @SystemApi Allows an application to delete packages.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.DELETE_PACKAGES"
android:label="@string/permlab_deletePackages"
android:description="@string/permdesc_deletePackages"
android:protectionLevel="signature|system" />
- <!-- Allows an application to move location of installed package.
+ <!-- @SystemApi Allows an application to move location of installed package.
@hide -->
<permission android:name="android.permission.MOVE_PACKAGE"
android:label="@string/permlab_movePackage"
android:description="@string/permdesc_movePackage"
android:protectionLevel="signature|system" />
- <!-- Allows an application to change whether an application component (other than its own) is
+ <!-- @SystemApi Allows an application to change whether an application component (other than its own) is
enabled or not.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"
@@ -2195,7 +2224,7 @@
android:description="@string/permdesc_accessSurfaceFlinger"
android:protectionLevel="signature" />
- <!-- Allows an application to take screen shots and more generally
+ <!-- @SystemApi Allows an application to take screen shots and more generally
get access to the frame buffer data.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.READ_FRAME_BUFFER"
@@ -2204,7 +2233,7 @@
android:protectionLevel="signature|system" />
<!-- Allows an application to use InputFlinger's low level features.
- <p>Not for use by third-party applications. -->
+ @hide -->
<permission android:name="android.permission.ACCESS_INPUT_FLINGER"
android:label="@string/permlab_accessInputFlinger"
android:description="@string/permdesc_accessInputFlinger"
@@ -2226,14 +2255,14 @@
android:description="@string/permdesc_controlWifiDisplay"
android:protectionLevel="signature" />
- <!-- Allows an application to capture audio output.
+ <!-- @SystemApi Allows an application to capture audio output.
<p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"
android:label="@string/permlab_captureAudioOutput"
android:description="@string/permdesc_captureAudioOutput"
android:protectionLevel="signature|system" />
- <!-- Allows an application to capture audio for hotword detection.
+ <!-- @SystemApi Allows an application to capture audio for hotword detection.
<p>Not for use by third-party applications.</p>
@hide -->
<permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD"
@@ -2241,7 +2270,7 @@
android:description="@string/permdesc_captureAudioHotword"
android:protectionLevel="signature|system" />
- <!-- Allows an application to modify audio routing and override policy decisions.
+ <!-- @SystemApi Allows an application to modify audio routing and override policy decisions.
<p>Not for use by third-party applications.</p>
@hide -->
<permission android:name="android.permission.MODIFY_AUDIO_ROUTING"
@@ -2249,21 +2278,21 @@
android:description="@string/permdesc_modifyAudioRouting"
android:protectionLevel="signature|system" />
- <!-- Allows an application to capture video output.
+ <!-- @SystemApi Allows an application to capture video output.
<p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
android:label="@string/permlab_captureVideoOutput"
android:description="@string/permdesc_captureVideoOutput"
android:protectionLevel="signature|system" />
- <!-- Allows an application to capture secure video output.
+ <!-- @SystemApi Allows an application to capture secure video output.
<p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT"
android:label="@string/permlab_captureSecureVideoOutput"
android:description="@string/permdesc_captureSecureVideoOutput"
android:protectionLevel="signature|system" />
- <!-- Allows an application to know what content is playing and control its playback.
+ <!-- @SystemApi Allows an application to know what content is playing and control its playback.
<p>Not for use by third-party applications due to privacy of media consumption</p> -->
<permission android:name="android.permission.MEDIA_CONTENT_CONTROL"
android:label="@string/permlab_mediaContentControl"
@@ -2277,7 +2306,7 @@
android:description="@string/permdesc_brick"
android:protectionLevel="signature" />
- <!-- Required to be able to reboot the device.
+ <!-- @SystemApi Required to be able to reboot the device.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.REBOOT"
android:label="@string/permlab_reboot"
@@ -2329,20 +2358,20 @@
android:description="@string/permdesc_broadcastWapPush"
android:protectionLevel="signature" />
- <!-- Allows an application to broadcast a SCORE_NETWORKS request.
+ <!-- @SystemApi Allows an application to broadcast a SCORE_NETWORKS request.
<p>Not for use by third-party applications. @hide -->
<permission android:name="android.permission.BROADCAST_SCORE_NETWORKS"
android:label="@string/permlab_broadcastScoreNetworks"
android:description="@string/permdesc_broadcastScoreNetworks"
android:protectionLevel="signature|system" />
- <!-- Not for use by third-party applications. -->
+ <!-- @SystemApi Not for use by third-party applications. -->
<permission android:name="android.permission.MASTER_CLEAR"
android:label="@string/permlab_masterClear"
android:description="@string/permdesc_masterClear"
android:protectionLevel="signature|system" />
- <!-- Allows an application to call any phone number, including emergency
+ <!-- @SystemApi Allows an application to call any phone number, including emergency
numbers, without going through the Dialer user interface for the user
to confirm the call being placed.
<p>Not for use by third-party applications. -->
@@ -2351,13 +2380,13 @@
android:description="@string/permdesc_callPrivileged"
android:protectionLevel="signature|system" />
- <!-- Allows an application to perform CDMA OTA provisioning @hide -->
+ <!-- @SystemApi Allows an application to perform CDMA OTA provisioning @hide -->
<permission android:name="android.permission.PERFORM_CDMA_PROVISIONING"
android:label="@string/permlab_performCdmaProvisioning"
android:description="@string/permdesc_performCdmaProvisioning"
android:protectionLevel="signature|system" />
- <!-- Allows enabling/disabling location update notifications from
+ <!-- @SystemApi Allows enabling/disabling location update notifications from
the radio.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CONTROL_LOCATION_UPDATES"
@@ -2365,7 +2394,7 @@
android:description="@string/permdesc_locationUpdates"
android:protectionLevel="signature|system" />
- <!-- Allows read/write access to the "properties" table in the checkin
+ <!-- @SystemApi Allows read/write access to the "properties" table in the checkin
database, to change values that get uploaded.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES"
@@ -2373,21 +2402,21 @@
android:description="@string/permdesc_checkinProperties"
android:protectionLevel="signature|system" />
- <!-- Allows an application to collect component usage
+ <!-- @SystemApi Allows an application to collect component usage
statistics @hide -->
<permission android:name="android.permission.PACKAGE_USAGE_STATS"
android:label="@string/permlab_pkgUsageStats"
android:description="@string/permdesc_pkgUsageStats"
android:protectionLevel="signature|system" />
- <!-- Allows an application to collect battery statistics -->
+ <!-- @SystemApi Allows an application to collect battery statistics -->
<permission android:name="android.permission.BATTERY_STATS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:label="@string/permlab_batteryStats"
android:description="@string/permdesc_batteryStats"
android:protectionLevel="signature|system" />
- <!-- Allows an application to control the backup and restore process.
+ <!-- @SystemApi Allows an application to control the backup and restore process.
<p>Not for use by third-party applications.
@hide pending API council -->
<permission android:name="android.permission.BACKUP"
@@ -2403,14 +2432,14 @@
android:description="@string/permdesc_confirm_full_backup"
android:protectionLevel="signature" />
- <!-- Must be required by a {@link android.widget.RemoteViewsService},
+ <!-- @SystemApi Must be required by a {@link android.widget.RemoteViewsService},
to ensure that only the system can bind to it. -->
<permission android:name="android.permission.BIND_REMOTEVIEWS"
android:label="@string/permlab_bindRemoteViews"
android:description="@string/permdesc_bindRemoteViews"
android:protectionLevel="signature|system" />
- <!-- Allows an application to tell the AppWidget service which application
+ <!-- @SystemApi Allows an application to tell the AppWidget service which application
can access AppWidget's data. The normal user flow is that a user
picks an AppWidget to go into a particular host, thereby giving that
host application access to the private data from the AppWidget app.
@@ -2422,14 +2451,14 @@
android:description="@string/permdesc_bindGadget"
android:protectionLevel="signature|system" />
- <!-- Private permission, to restrict who can bring up a dialog to add a new
+ <!-- @SystemApi Private permission, to restrict who can bring up a dialog to add a new
keyguard widget
@hide -->
<permission android:name="android.permission.BIND_KEYGUARD_APPWIDGET"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
android:protectionLevel="signature|system" />
- <!-- Internal permission allowing an application to query/set which
+ <!-- @SystemApi Internal permission allowing an application to query/set which
applications can bind AppWidgets.
@hide -->
<permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"
@@ -2445,7 +2474,7 @@
android:description="@string/permdesc_changeBackgroundDataSetting"
android:label="@string/permlab_changeBackgroundDataSetting" />
- <!-- This permission can be used on content providers to allow the global
+ <!-- @SystemApi This permission can be used on content providers to allow the global
search system to access their data. Typically it used when the
provider has some permissions protecting it (which global search
would not be expected to hold), and added as a read-only permission
@@ -2468,32 +2497,32 @@
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signature" />
- <!-- Internal permission to allows an application to read indexable data.
+ <!-- @SystemApi Internal permission to allows an application to read indexable data.
@hide -->
<permission android:name="android.permission.READ_SEARCH_INDEXABLES"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signature|system" />
- <!-- Allows applications to set a live wallpaper.
+ <!-- @SystemApi Allows applications to set a live wallpaper.
@hide XXX Change to signature once the picker is moved to its
own apk as Ghod Intended. -->
<permission android:name="android.permission.SET_WALLPAPER_COMPONENT"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signature|system" />
- <!-- Allows applications to read dream settings and dream state.
+ <!-- @SystemApi Allows applications to read dream settings and dream state.
@hide -->
<permission android:name="android.permission.READ_DREAM_STATE"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signature|system" />
- <!-- Allows applications to write dream settings, and start or stop dreaming.
+ <!-- @SystemApi Allows applications to write dream settings, and start or stop dreaming.
@hide -->
<permission android:name="android.permission.WRITE_DREAM_STATE"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signature|system" />
- <!-- Allow an application to read and write the cache partition.
+ <!-- @SystemApi Allow an application to read and write the cache partition.
@hide -->
<permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
android:label="@string/permlab_cache_filesystem"
@@ -2510,13 +2539,13 @@
android:description="@string/permlab_copyProtectedData"
android:protectionLevel="signature" />
- <!-- Internal permission protecting access to the encryption methods
+ <!-- @SystemApi Internal permission protecting access to the encryption methods
@hide
-->
<permission android:name="android.permission.CRYPT_KEEPER"
android:protectionLevel="signature|system" />
- <!-- Allows an application to read historical network usage for
+ <!-- @SystemApi Allows an application to read historical network usage for
specific networks and applications. @hide -->
<permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY"
android:label="@string/permlab_readNetworkUsageHistory"
@@ -2530,7 +2559,7 @@
android:description="@string/permdesc_manageNetworkPolicy"
android:protectionLevel="signature" />
- <!-- Allows an application to account its network traffic against other UIDs. Used
+ <!-- @SystemApi Allows an application to account its network traffic against other UIDs. Used
by system services like download manager and media server. Not for use by
third party apps. @hide -->
<permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING"
@@ -2538,7 +2567,7 @@
android:description="@string/permdesc_modifyNetworkAccounting"
android:protectionLevel="signature|system" />
- <!-- Allows an application to mark traffic as from another user for per user routing.
+ <!-- @SystemApi Allows an application to mark traffic as from another user for per user routing.
Used by system wide services like media server that execute delegated network connections
for users.
@hide
@@ -2555,7 +2584,7 @@
android:protectionLevel="signature" />
<uses-permission android:name="android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE"/>
- <!-- @hide Package verifier needs to have this permission before the PackageManager will
+ <!-- @SystemApi @hide Package verifier needs to have this permission before the PackageManager will
trust it to verify packages.
-->
<permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT"
@@ -2572,7 +2601,7 @@
android:description="@string/permdesc_bindPackageVerifier"
android:protectionLevel="signature" />
- <!-- Allows applications to access serial ports via the SerialManager.
+ <!-- @SystemApi Allows applications to access serial ports via the SerialManager.
@hide -->
<permission android:name="android.permission.SERIAL_PORT"
android:label="@string/permlab_serialPort"
@@ -2589,7 +2618,8 @@
android:label="@string/permlab_accessContentProvidersExternally"
android:description="@string/permdesc_accessContentProvidersExternally"
android:protectionLevel="signature" />
- <!-- Allows an application to hold an UpdateLock, recommending that a headless
+
+ <!-- @SystemApi Allows an application to hold an UpdateLock, recommending that a headless
OTA reboot *not* occur while the lock is held.
@hide -->
<permission android:name="android.permission.UPDATE_LOCK"
@@ -2597,7 +2627,7 @@
android:description="@string/permdesc_updateLock"
android:protectionLevel="signatureOrSystem" />
- <!-- Allows an application to read the current set of notifications, including
+ <!-- @SystemApi Allows an application to read the current set of notifications, including
any metadata and intents attached.
@hide -->
<permission android:name="android.permission.ACCESS_NOTIFICATIONS"
@@ -2626,13 +2656,20 @@
android:label="@string/permlab_trust_listener"
android:description="@string/permdesc_trust_listener" />
- <!-- Allows an application to provide a trust agent.
+ <!-- @SystemApi Allows an application to provide a trust agent.
@hide For security reasons, this is a platform-only permission. -->
<permission android:name="android.permission.PROVIDE_TRUST_AGENT"
android:protectionLevel="signatureOrSystem"
android:label="@string/permlab_provide_trust_agent"
android:description="@string/permdesc_provide_trust_agent" />
+ <!-- Allows an application to launch the trust agent settings activity.
+ @hide -->
+ <permission android:name="android.permission.LAUNCH_TRUST_AGENT_SETTINGS"
+ android:protectionLevel="signatureOrSystem"
+ android:label="@string/permlab_launch_trust_agent_settings"
+ android:description="@string/permdesc_launch_trust_agent_settings" />
+
<!-- Must be required by an {@link
android.service.trust.TrustAgentService},
to ensure that only the system can bind to it. -->
@@ -2658,7 +2695,7 @@
android:description="@string/permdesc_bindConditionProviderService"
android:protectionLevel="signature" />
- <!-- Allows an application to call into a carrier setup flow. It is up to the
+ <!-- @SystemApi Allows an application to call into a carrier setup flow. It is up to the
carrier setup application to enforce that this permission is required
@hide This is not a third-party API (intended for OEMs and system apps). -->
<permission android:name="android.permission.INVOKE_CARRIER_SETUP"
@@ -2666,14 +2703,14 @@
android:description="@string/permdesc_invokeCarrierSetup"
android:protectionLevel="signature|system" />
- <!-- Allows an application to listen for network condition observations.
+ <!-- @SystemApi Allows an application to listen for network condition observations.
@hide This is not a third-party API (intended for system apps). -->
<permission android:name="android.permission.ACCESS_NETWORK_CONDITIONS"
android:label="@string/permlab_accessNetworkConditions"
android:description="@string/permdesc_accessNetworkConditions"
android:protectionLevel="signature|system" />
- <!-- Allows an application to provision and access DRM certificates
+ <!-- @SystemApi Allows an application to provision and access DRM certificates
@hide This is not a third-party API (intended for system apps). -->
<permission android:name="android.permission.ACCESS_DRM_CERTIFICATES"
android:label="@string/permlab_accessDrmCertificates"
@@ -2697,7 +2734,8 @@
android:theme="@style/Theme.Holo.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
- android:multiprocess="true">
+ android:multiprocess="true"
+ android:documentLaunchMode="never">
<intent-filter>
<action android:name="android.intent.action.CHOOSER" />
<category android:name="android.intent.category.DEFAULT" />
@@ -2719,7 +2757,7 @@
</activity-alias>
<activity-alias android:name="com.android.internal.app.ForwardIntentToManagedProfile"
android:targetActivity="com.android.internal.app.IntentForwarderActivity"
- android:icon="@drawable/work_icon"
+ android:icon="@drawable/ic_afw_icon"
android:exported="true"
android:label="@string/managed_profile_label">
</activity-alias>
@@ -2803,7 +2841,7 @@
</activity>
<activity android:name="com.android.internal.app.RestrictionsPinActivity"
- android:theme="@style/Theme.Holo.Dialog.Alert"
+ android:theme="@style/Theme.Material.Light.Dialog.Alert"
android:excludeFromRecents="true"
android:windowSoftInputMode="adjustPan"
android:process=":ui">
@@ -2886,11 +2924,14 @@
</service>
<service android:name="com.android.server.MountServiceIdler"
- android:exported="false"
- android:permission="android.permission.BIND_IDLE_SERVICE" >
- <intent-filter>
- <action android:name="android.service.idle.IdleService" />
- </intent-filter>
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
+ <service
+ android:name="com.android.server.pm.BackgroundDexOptService"
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE">
</service>
</application>
diff --git a/core/res/assets/images/android-logo-mask.png b/core/res/assets/images/android-logo-mask.png
index 1e8ab95..ad40645 100644
--- a/core/res/assets/images/android-logo-mask.png
+++ b/core/res/assets/images/android-logo-mask.png
Binary files differ
diff --git a/core/res/assets/images/android-logo-shine.png b/core/res/assets/images/android-logo-shine.png
index 60144f1..cb65f22 100644
--- a/core/res/assets/images/android-logo-shine.png
+++ b/core/res/assets/images/android-logo-shine.png
Binary files differ
diff --git a/core/res/res/anim-land/task_close_enter.xml b/core/res/res/anim-land/task_close_enter.xml
deleted file mode 100644
index facc42b..0000000
--- a/core/res/res/anim-land/task_close_enter.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
-
- <alpha android:fromAlpha="0" android:toAlpha="1.0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="300"
- android:duration="400"/>
-
- <translate android:fromXDelta="-120%" android:toXDelta="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:startOffset="300"
- android:duration="400" />
-
- <scale android:fromXScale=".5" android:toXScale="1.0"
- android:fromYScale=".5" android:toYScale="1.0"
- android:pivotY="50%p" android:pivotX="0%p"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="300"
- android:duration="400" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_close_exit.xml b/core/res/res/anim-land/task_close_exit.xml
deleted file mode 100644
index e104c33..0000000
--- a/core/res/res/anim-land/task_close_exit.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
-
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="300"/>
-
- <translate android:fromXDelta="0" android:toXDelta="120%"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_cubic"
- android:duration="300"/>
-
- <scale android:fromXScale="1.0" android:toXScale="0.5"
- android:fromYScale="1.0" android:toYScale="0.5"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotY="50%p" android:pivotX="100%p"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="300" />
-
- <!-- This is needed to keep the animation running while task_open_enter completes -->
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:duration="700" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_open_enter.xml b/core/res/res/anim-land/task_open_enter.xml
deleted file mode 100644
index dc7c7a9..0000000
--- a/core/res/res/anim-land/task_open_enter.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
-
- <alpha android:fromAlpha="0" android:toAlpha="1.0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="300"
- android:duration="400"/>
-
- <translate android:fromXDelta="120%" android:toXDelta="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:startOffset="300"
- android:duration="400" />
-
- <scale android:fromXScale=".5" android:toXScale="1.0"
- android:fromYScale=".5" android:toYScale="1.0"
- android:pivotY="50%p" android:pivotX="100%p"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="300"
- android:duration="400" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_open_exit.xml b/core/res/res/anim-land/task_open_exit.xml
deleted file mode 100644
index 701afa6..0000000
--- a/core/res/res/anim-land/task_open_exit.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
-
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="300"/>
-
- <translate android:fromXDelta="0" android:toXDelta="-120%"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_cubic"
- android:duration="300"/>
-
- <scale android:fromXScale="1.0" android:toXScale="0.5"
- android:fromYScale="1.0" android:toYScale="0.5"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotY="50%p" android:pivotX="0%p"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="300" />
-
- <!-- This is needed to keep the animation running while task_open_enter completes -->
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:duration="700" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_close_enter.xml b/core/res/res/anim-sw720dp/task_close_enter.xml
deleted file mode 100644
index e25978b..0000000
--- a/core/res/res/anim-sw720dp/task_close_enter.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
-
- <alpha android:fromAlpha="0" android:toAlpha="1.0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="500"
- android:duration="400"/>
-
- <translate android:fromYDelta="-50%" android:toYDelta="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:startOffset="500"
- android:duration="400" />
-
- <scale android:fromXScale=".8" android:toXScale="1.0"
- android:fromYScale=".8" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="0%p"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="500"
- android:duration="400" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_close_exit.xml b/core/res/res/anim-sw720dp/task_close_exit.xml
deleted file mode 100644
index 2d7e2a6..0000000
--- a/core/res/res/anim-sw720dp/task_close_exit.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
-
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="350"/>
-
- <translate android:fromYDelta="0" android:toYDelta="50%"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_cubic"
- android:duration="350"/>
-
- <scale android:fromXScale="1.0" android:toXScale="0.8"
- android:fromYScale="1.0" android:toYScale="0.8"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="100%p"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="350" />
-
- <!-- This is needed to keep the animation running while task_close_enter completes -->
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:duration="900" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_open_enter.xml b/core/res/res/anim-sw720dp/task_open_enter.xml
deleted file mode 100644
index d583b6e..0000000
--- a/core/res/res/anim-sw720dp/task_open_enter.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
-
- <alpha android:fromAlpha="0" android:toAlpha="1.0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="500"
- android:duration="400"/>
-
- <translate android:fromYDelta="50%" android:toYDelta="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:startOffset="500"
- android:duration="400" />
-
- <scale android:fromXScale=".8" android:toXScale="1.0"
- android:fromYScale=".8" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="100%p"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="500"
- android:duration="400" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_open_exit.xml b/core/res/res/anim-sw720dp/task_open_exit.xml
deleted file mode 100644
index dd25a0c..0000000
--- a/core/res/res/anim-sw720dp/task_open_exit.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
-
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="350"/>
-
- <translate android:fromYDelta="0" android:toYDelta="-50%"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_cubic"
- android:duration="350"/>
-
- <scale android:fromXScale="1.0" android:toXScale="0.8"
- android:fromYScale="1.0" android:toYScale="0.8"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="0%p"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="350" />
-
- <!-- This is needed to keep the animation running while task_open_enter completes -->
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:duration="900" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim/activity_close_enter.xml b/core/res/res/anim/activity_close_enter.xml
index 84e4a19..a67b0ca 100644
--- a/core/res/res/anim/activity_close_enter.xml
+++ b/core/res/res/anim/activity_close_enter.xml
@@ -18,7 +18,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:zAdjustment="normal">
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+ <alpha android:fromAlpha="0.7" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:duration="300"/>
+ android:interpolator="@interpolator/linear_out_slow_in"
+ android:duration="250"/>
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/activity_close_exit.xml b/core/res/res/anim/activity_close_exit.xml
index 32f6d38..52c3adf 100644
--- a/core/res/res/anim/activity_close_exit.xml
+++ b/core/res/res/anim/activity_close_exit.xml
@@ -20,13 +20,13 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" android:zAdjustment="top">
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:interpolator="@interpolator/decelerate_cubic"
+ android:interpolator="@interpolator/accelerate_quart"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:startOffset="100"
+ android:duration="150"/>
+ <translate android:fromYDelta="0%" android:toYDelta="5%"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:duration="300"/>
- <scale android:fromXScale="1.0" android:toXScale=".8"
- android:fromYScale="1.0" android:toYScale=".8"
- android:pivotX="50%p" android:pivotY="50%p"
- android:interpolator="@interpolator/decelerate_cubic"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:duration="300"/>
+ android:interpolator="@interpolator/accelerate_quint"
+ android:duration="250"/>
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/activity_open_enter.xml b/core/res/res/anim/activity_open_enter.xml
index d553bdf..1d949d2 100644
--- a/core/res/res/anim/activity_open_enter.xml
+++ b/core/res/res/anim/activity_open_enter.xml
@@ -21,15 +21,12 @@
android:shareInterpolator="false"
android:zAdjustment="top">
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:interpolator="@interpolator/decelerate_cubic"
+ android:interpolator="@interpolator/decelerate_quart"
android:fillEnabled="true"
android:fillBefore="false" android:fillAfter="true"
- android:duration="300"/>
- <scale android:fromXScale=".8" android:toXScale="1.0"
- android:fromYScale=".8" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="50%p"
- android:interpolator="@interpolator/decelerate_cubic"
- android:fillEnabled="true"
- android:fillBefore="false" android:fillAfter="true"
- android:duration="300"/>
+ android:duration="200"/>
+ <translate android:fromYDelta="8%" android:toYDelta="0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:duration="350"/>
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/activity_open_exit.xml b/core/res/res/anim/activity_open_exit.xml
index 2d105d1..3a84197 100644
--- a/core/res/res/anim/activity_open_exit.xml
+++ b/core/res/res/anim/activity_open_exit.xml
@@ -19,8 +19,8 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ff000000" android:zAdjustment="normal">
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.7"
android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:duration="300"/>
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="217"/>
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/button_state_list_anim_quantum.xml b/core/res/res/anim/button_state_list_anim_material.xml
similarity index 100%
rename from core/res/res/anim/button_state_list_anim_quantum.xml
rename to core/res/res/anim/button_state_list_anim_material.xml
diff --git a/core/res/res/anim/popup_enter_quantum.xml b/core/res/res/anim/popup_enter_material.xml
similarity index 100%
rename from core/res/res/anim/popup_enter_quantum.xml
rename to core/res/res/anim/popup_enter_material.xml
diff --git a/core/res/res/anim/popup_exit_quantum.xml b/core/res/res/anim/popup_exit_material.xml
similarity index 100%
rename from core/res/res/anim/popup_exit_quantum.xml
rename to core/res/res/anim/popup_exit_material.xml
diff --git a/core/res/res/anim/task_close_enter.xml b/core/res/res/anim/task_close_enter.xml
index 9a747a1..b07f470 100644
--- a/core/res/res/anim/task_close_enter.xml
+++ b/core/res/res/anim/task_close_enter.xml
@@ -18,25 +18,25 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
+ android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
- <alpha android:fromAlpha="0" android:toAlpha="1.0"
+ <alpha android:fromAlpha="0.6" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="300"
- android:duration="400"/>
+ android:interpolator="@interpolator/decelerate_cubic"
+ android:startOffset="600"
+ android:duration="133"/>
- <translate android:fromYDelta="-120%" android:toYDelta="0"
+ <translate android:fromYDelta="10%" android:toYDelta="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quint"
+ android:interpolator="@interpolator/decelerate_cubic"
android:startOffset="300"
- android:duration="400" />
+ android:duration="433" />
- <scale android:fromXScale=".5" android:toXScale="1.0"
- android:fromYScale=".5" android:toYScale="1.0"
+ <scale android:fromXScale=".9" android:toXScale="1.0"
+ android:fromYScale=".9" android:toYScale="1.0"
android:pivotX="50%p" android:pivotY="0%p"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
+ android:interpolator="@interpolator/fast_out_slow_in"
android:startOffset="300"
- android:duration="400" />
+ android:duration="433" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml
index 35b1aa3..d23c74f 100644
--- a/core/res/res/anim/task_close_exit.xml
+++ b/core/res/res/anim/task_close_exit.xml
@@ -18,24 +18,18 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+ android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
<alpha android:fromAlpha="1.0" android:toAlpha="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/accelerate_quad"
- android:duration="300"/>
+ android:startOffset="250"
+ android:duration="167"/>
- <translate android:fromYDelta="0" android:toYDelta="120%"
+ <translate android:fromYDelta="0" android:toYDelta="110%"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_cubic"
- android:duration="300"/>
-
- <scale android:fromXScale="1.0" android:toXScale="0.5"
- android:fromYScale="1.0" android:toYScale="0.5"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="100%p"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="300" />
+ android:interpolator="@interpolator/accelerate_quint"
+ android:duration="417"/>
<!-- This is needed to keep the animation running while task_open_enter completes -->
<alpha android:fromAlpha="1.0" android:toAlpha="1.0"
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index 5e4ae18..8321ea4 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -22,21 +22,13 @@
<alpha android:fromAlpha="0" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
+ android:interpolator="@interpolator/decelerate_quart"
android:startOffset="300"
- android:duration="400"/>
+ android:duration="167"/>
- <translate android:fromYDelta="120%" android:toYDelta="0"
+ <translate android:fromYDelta="110%" android:toYDelta="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quint"
android:startOffset="300"
- android:duration="400" />
-
- <scale android:fromXScale=".5" android:toXScale="1.0"
- android:fromYScale=".5" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="100%p"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="300"
- android:duration="400" />
+ android:duration="417" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml
index 0ba35d7..78d0fb0 100644
--- a/core/res/res/anim/task_open_exit.xml
+++ b/core/res/res/anim/task_open_exit.xml
@@ -20,22 +20,22 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="300"/>
-
- <translate android:fromYDelta="0" android:toYDelta="-120%"
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.6"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/accelerate_cubic"
- android:duration="300"/>
+ android:duration="133"/>
- <scale android:fromXScale="1.0" android:toXScale="0.5"
- android:fromYScale="1.0" android:toYScale="0.5"
+ <translate android:fromYDelta="0" android:toYDelta="10%"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="0%p"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="300" />
+ android:interpolator="@interpolator/accelerate_cubic"
+ android:duration="433"/>
+
+ <scale android:fromXScale="1.0" android:toXScale="0.9"
+ android:fromYScale="1.0" android:toYScale="0.9"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="433" />
<!-- This is needed to keep the animation running while task_open_enter completes -->
<alpha android:fromAlpha="1.0" android:toAlpha="1.0"
diff --git a/core/res/res/anim/wallpaper_open_enter.xml b/core/res/res/anim/wallpaper_open_enter.xml
index 12a1bdf..e70f0e7 100644
--- a/core/res/res/anim/wallpaper_open_enter.xml
+++ b/core/res/res/anim/wallpaper_open_enter.xml
@@ -21,5 +21,5 @@
android:detachWallpaper="true" android:shareInterpolator="false" android:zAdjustment="normal">
<alpha android:fromAlpha="1.0" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:duration="375"/>
+ android:duration="225"/>
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/wallpaper_open_exit.xml b/core/res/res/anim/wallpaper_open_exit.xml
index b0f97d1..696912b 100644
--- a/core/res/res/anim/wallpaper_open_exit.xml
+++ b/core/res/res/anim/wallpaper_open_exit.xml
@@ -19,14 +19,22 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" android:zAdjustment="top">
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:interpolator="@interpolator/accelerate_decelerate"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:duration="200" />
- <scale android:fromXScale="1.0" android:toXScale="0.5"
- android:fromYScale="1.0" android:toYScale="0.5"
- android:pivotX="50%p" android:pivotY="50%p"
- android:interpolator="@interpolator/decelerate_quad"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:duration="375" />
+
+ <alpha android:fromAlpha="1.0" android:toAlpha="0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/accelerate_quad"
+ android:startOffset="250"
+ android:duration="167"/>
+
+ <translate android:fromYDelta="0" android:toYDelta="110%"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_linear_in"
+ android:duration="225"/>
+
+ <scale android:fromXScale="1.0" android:toXScale="1.0"
+ android:fromYScale="1.0" android:toYScale="1.0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="225" />
</set>
\ No newline at end of file
diff --git a/core/res/res/animator/fragment_open_enter.xml b/core/res/res/animator/fragment_open_enter.xml
index 8cd0e4e..4ae24b9 100644
--- a/core/res/res/animator/fragment_open_enter.xml
+++ b/core/res/res/animator/fragment_open_enter.xml
@@ -19,13 +19,13 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:interpolator="@interpolator/decelerate_cubic"
- android:valueFrom="0.8" android:valueTo="1.0"
+ android:valueFrom="0.95" android:valueTo="1.0"
android:valueType="floatType"
android:propertyName="scaleY"
android:duration="300"/>
<objectAnimator
android:interpolator="@interpolator/decelerate_cubic"
- android:valueFrom="0.8" android:valueTo="1.0"
+ android:valueFrom="0.95" android:valueTo="1.0"
android:valueType="floatType"
android:propertyName="scaleX"
android:duration="300"/>
diff --git a/core/res/res/color/background_cache_hint_selector_quantum_light.xml b/core/res/res/color/background_cache_hint_selector_material_dark.xml
similarity index 95%
copy from core/res/res/color/background_cache_hint_selector_quantum_light.xml
copy to core/res/res/color/background_cache_hint_selector_material_dark.xml
index fb940a9..e7c9426 100644
--- a/core/res/res/color/background_cache_hint_selector_quantum_light.xml
+++ b/core/res/res/color/background_cache_hint_selector_material_dark.xml
@@ -15,6 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_accelerated="false" android:color="@android:color/background_quantum_light" />
+ <item android:state_accelerated="false" android:color="@android:color/background_material_dark" />
<item android:color="@android:color/transparent" />
</selector>
diff --git a/core/res/res/color/background_cache_hint_selector_quantum_light.xml b/core/res/res/color/background_cache_hint_selector_material_light.xml
similarity index 95%
rename from core/res/res/color/background_cache_hint_selector_quantum_light.xml
rename to core/res/res/color/background_cache_hint_selector_material_light.xml
index fb940a9..96f1f59 100644
--- a/core/res/res/color/background_cache_hint_selector_quantum_light.xml
+++ b/core/res/res/color/background_cache_hint_selector_material_light.xml
@@ -15,6 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_accelerated="false" android:color="@android:color/background_quantum_light" />
+ <item android:state_accelerated="false" android:color="@android:color/background_material_light" />
<item android:color="@android:color/transparent" />
</selector>
diff --git a/core/res/res/color/background_cache_hint_selector_quantum_dark.xml b/core/res/res/color/background_cache_hint_selector_quantum_dark.xml
deleted file mode 100644
index ab66501..0000000
--- a/core/res/res/color/background_cache_hint_selector_quantum_dark.xml
+++ /dev/null
@@ -1,20 +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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_accelerated="false" android:color="@android:color/background_quantum_dark" />
- <item android:color="@android:color/transparent" />
-</selector>
diff --git a/core/res/res/color/btn_default_quantum_dark.xml b/core/res/res/color/btn_default_material_dark.xml
similarity index 89%
rename from core/res/res/color/btn_default_quantum_dark.xml
rename to core/res/res/color/btn_default_material_dark.xml
index ec0f140..59555ae 100644
--- a/core/res/res/color/btn_default_quantum_dark.xml
+++ b/core/res/res/color/btn_default_material_dark.xml
@@ -15,6 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:alpha="0.5" android:color="@color/button_quantum_dark"/>
- <item android:color="@color/button_quantum_dark"/>
+ <item android:state_enabled="false" android:alpha="0.5" android:color="@color/button_material_dark"/>
+ <item android:color="@color/button_material_dark"/>
</selector>
diff --git a/core/res/res/color/btn_default_quantum_dark.xml b/core/res/res/color/btn_default_material_light.xml
similarity index 88%
copy from core/res/res/color/btn_default_quantum_dark.xml
copy to core/res/res/color/btn_default_material_light.xml
index ec0f140..6511a22 100644
--- a/core/res/res/color/btn_default_quantum_dark.xml
+++ b/core/res/res/color/btn_default_material_light.xml
@@ -15,6 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:alpha="0.5" android:color="@color/button_quantum_dark"/>
- <item android:color="@color/button_quantum_dark"/>
+ <item android:state_enabled="false" android:alpha="0.5" android:color="@color/button_material_light"/>
+ <item android:color="@color/button_material_light"/>
</selector>
diff --git a/core/res/res/color/btn_default_quantum_light.xml b/core/res/res/color/btn_default_quantum_light.xml
deleted file mode 100644
index 9536d24..0000000
--- a/core/res/res/color/btn_default_quantum_light.xml
+++ /dev/null
@@ -1,20 +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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:alpha="0.5" android:color="@color/button_quantum_light"/>
- <item android:color="@color/button_quantum_light"/>
-</selector>
diff --git a/core/res/res/color/btn_default_quantum_dark.xml b/core/res/res/color/primary_text_disable_only_material_dark.xml
similarity index 85%
copy from core/res/res/color/btn_default_quantum_dark.xml
copy to core/res/res/color/primary_text_disable_only_material_dark.xml
index ec0f140..cf7acaa 100644
--- a/core/res/res/color/btn_default_quantum_dark.xml
+++ b/core/res/res/color/primary_text_disable_only_material_dark.xml
@@ -15,6 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:alpha="0.5" android:color="@color/button_quantum_dark"/>
- <item android:color="@color/button_quantum_dark"/>
+ <item android:state_enabled="false" android:alpha="0.5" android:color="@android:color/bright_foreground_material_dark"/>
+ <item android:color="@android:color/bright_foreground_material_dark"/>
</selector>
diff --git a/core/res/res/color/btn_default_quantum_dark.xml b/core/res/res/color/primary_text_disable_only_material_light.xml
similarity index 85%
copy from core/res/res/color/btn_default_quantum_dark.xml
copy to core/res/res/color/primary_text_disable_only_material_light.xml
index ec0f140..bf5d2c0 100644
--- a/core/res/res/color/btn_default_quantum_dark.xml
+++ b/core/res/res/color/primary_text_disable_only_material_light.xml
@@ -15,6 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:alpha="0.5" android:color="@color/button_quantum_dark"/>
- <item android:color="@color/button_quantum_dark"/>
+ <item android:state_enabled="false" android:alpha="0.5" android:color="@android:color/bright_foreground_material_light"/>
+ <item android:color="@android:color/bright_foreground_material_light"/>
</selector>
diff --git a/core/res/res/color/primary_text_disable_only_quantum_dark.xml b/core/res/res/color/primary_text_disable_only_quantum_dark.xml
deleted file mode 100644
index 60a91f2..0000000
--- a/core/res/res/color/primary_text_disable_only_quantum_dark.xml
+++ /dev/null
@@ -1,20 +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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:alpha="0.5" android:color="@android:color/bright_foreground_quantum_dark"/>
- <item android:color="@android:color/bright_foreground_quantum_dark"/>
-</selector>
diff --git a/core/res/res/color/primary_text_disable_only_quantum_light.xml b/core/res/res/color/primary_text_disable_only_quantum_light.xml
deleted file mode 100644
index ced9051..0000000
--- a/core/res/res/color/primary_text_disable_only_quantum_light.xml
+++ /dev/null
@@ -1,20 +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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:alpha="0.5" android:color="@android:color/bright_foreground_quantum_light"/>
- <item android:color="@android:color/bright_foreground_quantum_light"/>
-</selector>
diff --git a/core/res/res/color/primary_text_quantum_dark.xml b/core/res/res/color/primary_text_material_dark.xml
similarity index 86%
copy from core/res/res/color/primary_text_quantum_dark.xml
copy to core/res/res/color/primary_text_material_dark.xml
index 1fcd0e3..caef9d0 100644
--- a/core/res/res/color/primary_text_quantum_dark.xml
+++ b/core/res/res/color/primary_text_material_dark.xml
@@ -15,6 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:alpha="0.5" android:color="@color/primary_text_default_quantum_dark"/>
- <item android:color="@color/primary_text_default_quantum_dark"/>
+ <item android:state_enabled="false" android:alpha="0.5" android:color="@color/primary_text_default_material_dark"/>
+ <item android:color="@color/primary_text_default_material_dark"/>
</selector>
diff --git a/core/res/res/color/primary_text_quantum_dark.xml b/core/res/res/color/primary_text_material_light.xml
similarity index 86%
rename from core/res/res/color/primary_text_quantum_dark.xml
rename to core/res/res/color/primary_text_material_light.xml
index 1fcd0e3..81a593b 100644
--- a/core/res/res/color/primary_text_quantum_dark.xml
+++ b/core/res/res/color/primary_text_material_light.xml
@@ -15,6 +15,6 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:alpha="0.5" android:color="@color/primary_text_default_quantum_dark"/>
- <item android:color="@color/primary_text_default_quantum_dark"/>
+ <item android:state_enabled="false" android:alpha="0.5" android:color="@color/primary_text_default_material_light"/>
+ <item android:color="@color/primary_text_default_material_light"/>
</selector>
diff --git a/core/res/res/color/primary_text_quantum_light.xml b/core/res/res/color/primary_text_quantum_light.xml
deleted file mode 100644
index 1ec1634..0000000
--- a/core/res/res/color/primary_text_quantum_light.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:alpha="0.5" android:color="@color/primary_text_default_quantum_light"/>
- <item android:color="@color/primary_text_default_quantum_light"/>
-</selector>
diff --git a/core/res/res/color/search_url_text_quantum_dark.xml b/core/res/res/color/search_url_text_material_dark.xml
similarity index 100%
rename from core/res/res/color/search_url_text_quantum_dark.xml
rename to core/res/res/color/search_url_text_material_dark.xml
diff --git a/core/res/res/color/search_url_text_quantum_light.xml b/core/res/res/color/search_url_text_material_light.xml
similarity index 100%
rename from core/res/res/color/search_url_text_quantum_light.xml
rename to core/res/res/color/search_url_text_material_light.xml
diff --git a/core/res/res/drawable-hdpi/ab_share_pack_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_share_pack_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ab_share_pack_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/ab_share_pack_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ab_solid_shadow_qntm_alpha.9.png b/core/res/res/drawable-hdpi/ab_solid_shadow_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ab_solid_shadow_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/ab_solid_shadow_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_cab_done_qntm_alpha.9.png b/core/res/res/drawable-hdpi/btn_cab_done_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_cab_done_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/btn_cab_done_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_000.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_001.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_002.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_003.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_004.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_005.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_006.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_007.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_008.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_009.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_010.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_011.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_012.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_013.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_014.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_off_qntm_015.png
rename to core/res/res/drawable-hdpi/btn_check_to_off_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_000.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_001.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_002.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_003.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_004.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_005.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_006.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_007.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_008.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_009.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_010.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_011.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_012.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_013.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_014.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_check_to_on_qntm_015.png
rename to core/res/res/drawable-hdpi/btn_check_to_on_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_code_lock_default_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_code_lock_default_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_code_lock_default_qntm_alpha.png
rename to core/res/res/drawable-hdpi/btn_code_lock_default_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_code_lock_touched_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_code_lock_touched_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_code_lock_touched_qntm_alpha.png
rename to core/res/res/drawable-hdpi/btn_code_lock_touched_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_qntm_alpha.9.png b/core/res/res/drawable-hdpi/btn_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/btn_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_000.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_001.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_002.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_003.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_004.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_005.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_006.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_007.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_008.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_009.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_010.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_011.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_012.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_013.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_014.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_off_qntm_015.png
rename to core/res/res/drawable-hdpi/btn_radio_to_off_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_000.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_001.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_002.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_003.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_004.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_005.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_006.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_007.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_008.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_009.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_010.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_011.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_012.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_013.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_014.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_radio_to_on_qntm_015.png
rename to core/res/res/drawable-hdpi/btn_radio_to_on_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_rating_star_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_rating_star_off_qntm_alpha.png
rename to core/res/res/drawable-hdpi/btn_rating_star_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_rating_star_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_rating_star_on_qntm_alpha.png
rename to core/res/res/drawable-hdpi/btn_rating_star_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_star_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_star_qntm_alpha.png
rename to core/res/res/drawable-hdpi/btn_star_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_000.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_001.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_002.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_003.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_004.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_005.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_006.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_007.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_008.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_009.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_010.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_011.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_012.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_013.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_off_qntm_014.png
rename to core/res/res/drawable-hdpi/btn_switch_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_000.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_001.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_002.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_003.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_004.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_005.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_006.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_007.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_008.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_009.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_010.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_011.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_012.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_013.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_switch_to_on_qntm_014.png
rename to core/res/res/drawable-hdpi/btn_switch_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-hdpi/btn_toggle_indicator_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_toggle_indicator_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/btn_toggle_indicator_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-hdpi/btn_toggle_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/btn_toggle_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/btn_toggle_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
index 17acfc5..c5c0e97 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png
index 17acfc5..c5c0e97 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png
index 9b8ca22..3b31225 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png
index 9b8ca22..3b31225 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png
index bc20f6c..b65009e 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png
index bc20f6c..b65009e 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png
index 571819b..a2dfcae 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png
index 571819b..c3fda0e 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
index 1f83b5a..bae60a7 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png
index 1f83b5a..bae60a7 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png
index 733cf45..a9653b0 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png
index 733cf45..a9653b0 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png
index 2265de4..394cb5e 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png
index 2265de4..394cb5e 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png
index f3ada58..aa23c6e 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png
index f3ada58..028b3b8 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_background_mtrl_mult.9.png b/core/res/res/drawable-hdpi/dialog_background_mtrl_mult.9.png
new file mode 100644
index 0000000..0c3c3b4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/expander_close_qntm_alpha.9.png b/core/res/res/drawable-hdpi/expander_close_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/expander_close_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/expander_close_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/expander_open_qntm_alpha.9.png b/core/res/res/drawable-hdpi/expander_open_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/expander_open_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/expander_open_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/fastscroll_thumb_qntm_alpha.png b/core/res/res/drawable-hdpi/fastscroll_thumb_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/fastscroll_thumb_qntm_alpha.png
rename to core/res/res/drawable-hdpi/fastscroll_thumb_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/fastscroll_track_qntm_alpha.9.png b/core/res/res/drawable-hdpi/fastscroll_track_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/fastscroll_track_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/fastscroll_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_ab_back_qntm_am_alpha.png b/core/res/res/drawable-hdpi/ic_ab_back_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_ab_back_qntm_am_alpha.png
rename to core/res/res/drawable-hdpi/ic_ab_back_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_afw_icon.png b/core/res/res/drawable-hdpi/ic_afw_icon.png
new file mode 100644
index 0000000..fc986fe
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_afw_icon.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_cab_done_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_cab_done_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_cab_done_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_cab_done_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_clear_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_clear_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_clear_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_clear_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_commit_search_api_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_commit_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_commit_search_api_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_commit_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_dialog_alert_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_dialog_alert_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_dialog_alert_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_dialog_alert_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_find_next_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_find_next_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_find_next_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_find_next_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_find_previous_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_find_previous_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_find_previous_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_find_previous_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_go_search_api_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_go_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_go_search_api_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_go_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_disabled_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_disabled_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_media_route_disabled_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_media_route_disabled_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_off_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_media_route_off_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_media_route_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_0_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_on_0_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_media_route_on_0_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_media_route_on_0_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_1_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_on_1_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_media_route_on_1_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_media_route_on_1_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_2_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_on_2_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_media_route_on_2_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_media_route_on_2_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_media_route_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_media_route_on_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_media_route_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_copy_qntm_am_alpha.png b/core/res/res/drawable-hdpi/ic_menu_copy_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_copy_qntm_am_alpha.png
rename to core/res/res/drawable-hdpi/ic_menu_copy_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_cut_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_menu_cut_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_cut_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_menu_cut_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_find_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_menu_find_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_find_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_menu_find_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_moreoverflow_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_menu_moreoverflow_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_moreoverflow_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_menu_moreoverflow_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_paste_qntm_am_alpha.png b/core/res/res/drawable-hdpi/ic_menu_paste_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_paste_qntm_am_alpha.png
rename to core/res/res/drawable-hdpi/ic_menu_paste_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_search_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_menu_search_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_search_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_menu_search_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_selectall_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_menu_selectall_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_selectall_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_menu_selectall_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_menu_share_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_menu_share_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_menu_share_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_menu_share_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_search_api_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_search_api_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_voice_search_api_qntm_alpha.png b/core/res/res/drawable-hdpi/ic_voice_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/ic_voice_search_api_qntm_alpha.png
rename to core/res/res/drawable-hdpi/ic_voice_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_up_qntm_alpha.png b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_up_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_up_qntm_alpha.png
rename to core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_up_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default_qntm_alpha.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_default_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/indicator_code_lock_point_area_default_qntm_alpha.png
rename to core/res/res/drawable-hdpi/indicator_code_lock_point_area_default_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_point_area_qntm_alpha.png b/core/res/res/drawable-hdpi/indicator_code_lock_point_area_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/indicator_code_lock_point_area_qntm_alpha.png
rename to core/res/res/drawable-hdpi/indicator_code_lock_point_area_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_divider_qntm_alpha.9.png b/core/res/res/drawable-hdpi/list_divider_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/list_divider_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/list_divider_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_section_divider_qntm_alpha.9.png b/core/res/res/drawable-hdpi/list_section_divider_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/list_section_divider_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/list_section_divider_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_accessibility_features.png b/core/res/res/drawable-hdpi/perm_group_accessibility_features.png
index 7a1948e..c2b5960 100644
--- a/core/res/res/drawable-hdpi/perm_group_accessibility_features.png
+++ b/core/res/res/drawable-hdpi/perm_group_accessibility_features.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_accounts.png b/core/res/res/drawable-hdpi/perm_group_accounts.png
index 68a7c88..5ac28e7 100644
--- a/core/res/res/drawable-hdpi/perm_group_accounts.png
+++ b/core/res/res/drawable-hdpi/perm_group_accounts.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_affects_battery.png b/core/res/res/drawable-hdpi/perm_group_affects_battery.png
index 14adad1..945b4686 100644
--- a/core/res/res/drawable-hdpi/perm_group_affects_battery.png
+++ b/core/res/res/drawable-hdpi/perm_group_affects_battery.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_app_info.png b/core/res/res/drawable-hdpi/perm_group_app_info.png
index a263d33..754529e 100644
--- a/core/res/res/drawable-hdpi/perm_group_app_info.png
+++ b/core/res/res/drawable-hdpi/perm_group_app_info.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_audio_settings.png b/core/res/res/drawable-hdpi/perm_group_audio_settings.png
index 4e152af..7e5808a 100644
--- a/core/res/res/drawable-hdpi/perm_group_audio_settings.png
+++ b/core/res/res/drawable-hdpi/perm_group_audio_settings.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_bluetooth.png b/core/res/res/drawable-hdpi/perm_group_bluetooth.png
index 22ab06a..dac7071 100644
--- a/core/res/res/drawable-hdpi/perm_group_bluetooth.png
+++ b/core/res/res/drawable-hdpi/perm_group_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_bookmarks.png b/core/res/res/drawable-hdpi/perm_group_bookmarks.png
index 069bd85..0cb0c1d 100644
--- a/core/res/res/drawable-hdpi/perm_group_bookmarks.png
+++ b/core/res/res/drawable-hdpi/perm_group_bookmarks.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_calendar.png b/core/res/res/drawable-hdpi/perm_group_calendar.png
index 8fe55e7..1ef032f 100644
--- a/core/res/res/drawable-hdpi/perm_group_calendar.png
+++ b/core/res/res/drawable-hdpi/perm_group_calendar.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_camera.png b/core/res/res/drawable-hdpi/perm_group_camera.png
index 0203147..fb5a2f5 100644
--- a/core/res/res/drawable-hdpi/perm_group_camera.png
+++ b/core/res/res/drawable-hdpi/perm_group_camera.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_device_alarms.png b/core/res/res/drawable-hdpi/perm_group_device_alarms.png
index 4010c7a..f38c5fe 100644
--- a/core/res/res/drawable-hdpi/perm_group_device_alarms.png
+++ b/core/res/res/drawable-hdpi/perm_group_device_alarms.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_display.png b/core/res/res/drawable-hdpi/perm_group_display.png
index f60c7e2..c10c5d8 100644
--- a/core/res/res/drawable-hdpi/perm_group_display.png
+++ b/core/res/res/drawable-hdpi/perm_group_display.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_location.png b/core/res/res/drawable-hdpi/perm_group_location.png
index 2cc0ba6..6989b16 100644
--- a/core/res/res/drawable-hdpi/perm_group_location.png
+++ b/core/res/res/drawable-hdpi/perm_group_location.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_messages.png b/core/res/res/drawable-hdpi/perm_group_messages.png
index 013bc8f..21929b6 100644
--- a/core/res/res/drawable-hdpi/perm_group_messages.png
+++ b/core/res/res/drawable-hdpi/perm_group_messages.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_microphone.png b/core/res/res/drawable-hdpi/perm_group_microphone.png
index c94b0ba..9f8a681 100644
--- a/core/res/res/drawable-hdpi/perm_group_microphone.png
+++ b/core/res/res/drawable-hdpi/perm_group_microphone.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_network.png b/core/res/res/drawable-hdpi/perm_group_network.png
index f7907ef..0ecb7b2 100644
--- a/core/res/res/drawable-hdpi/perm_group_network.png
+++ b/core/res/res/drawable-hdpi/perm_group_network.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_personal_info.png b/core/res/res/drawable-hdpi/perm_group_personal_info.png
index dcfb160..e1b8a5b 100644
--- a/core/res/res/drawable-hdpi/perm_group_personal_info.png
+++ b/core/res/res/drawable-hdpi/perm_group_personal_info.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_phone_calls.png b/core/res/res/drawable-hdpi/perm_group_phone_calls.png
index 1decd84..8fa802e 100644
--- a/core/res/res/drawable-hdpi/perm_group_phone_calls.png
+++ b/core/res/res/drawable-hdpi/perm_group_phone_calls.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_screenlock.png b/core/res/res/drawable-hdpi/perm_group_screenlock.png
index 6abde49..b5a19ee 100644
--- a/core/res/res/drawable-hdpi/perm_group_screenlock.png
+++ b/core/res/res/drawable-hdpi/perm_group_screenlock.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_shortrange_network.png b/core/res/res/drawable-hdpi/perm_group_shortrange_network.png
index f7907ef..99ca933 100644
--- a/core/res/res/drawable-hdpi/perm_group_shortrange_network.png
+++ b/core/res/res/drawable-hdpi/perm_group_shortrange_network.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_social_info.png b/core/res/res/drawable-hdpi/perm_group_social_info.png
index e7e2488..dcf67e4 100644
--- a/core/res/res/drawable-hdpi/perm_group_social_info.png
+++ b/core/res/res/drawable-hdpi/perm_group_social_info.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_status_bar.png b/core/res/res/drawable-hdpi/perm_group_status_bar.png
index 73760b2..e3f6ed9 100644
--- a/core/res/res/drawable-hdpi/perm_group_status_bar.png
+++ b/core/res/res/drawable-hdpi/perm_group_status_bar.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_storage.png b/core/res/res/drawable-hdpi/perm_group_storage.png
index 642ce20..598e1cc 100644
--- a/core/res/res/drawable-hdpi/perm_group_storage.png
+++ b/core/res/res/drawable-hdpi/perm_group_storage.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_sync_settings.png b/core/res/res/drawable-hdpi/perm_group_sync_settings.png
index 0bc1506..1ca6b17 100644
--- a/core/res/res/drawable-hdpi/perm_group_sync_settings.png
+++ b/core/res/res/drawable-hdpi/perm_group_sync_settings.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_system_clock.png b/core/res/res/drawable-hdpi/perm_group_system_clock.png
index 7e4e293..3dd4682 100644
--- a/core/res/res/drawable-hdpi/perm_group_system_clock.png
+++ b/core/res/res/drawable-hdpi/perm_group_system_clock.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_system_tools.png b/core/res/res/drawable-hdpi/perm_group_system_tools.png
index 00a4c03..ae1ba2a 100644
--- a/core/res/res/drawable-hdpi/perm_group_system_tools.png
+++ b/core/res/res/drawable-hdpi/perm_group_system_tools.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_user_dictionary.png b/core/res/res/drawable-hdpi/perm_group_user_dictionary.png
index fc41348..62fbcdc 100644
--- a/core/res/res/drawable-hdpi/perm_group_user_dictionary.png
+++ b/core/res/res/drawable-hdpi/perm_group_user_dictionary.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_user_dictionary_write.png b/core/res/res/drawable-hdpi/perm_group_user_dictionary_write.png
index 7fa88aa..c62dd4c 100644
--- a/core/res/res/drawable-hdpi/perm_group_user_dictionary_write.png
+++ b/core/res/res/drawable-hdpi/perm_group_user_dictionary_write.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_voicemail.png b/core/res/res/drawable-hdpi/perm_group_voicemail.png
index 0ce5d1d..3b245d6 100644
--- a/core/res/res/drawable-hdpi/perm_group_voicemail.png
+++ b/core/res/res/drawable-hdpi/perm_group_voicemail.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/perm_group_wallpaper.png b/core/res/res/drawable-hdpi/perm_group_wallpaper.png
index 5db0361..e40c4f0 100644
--- a/core/res/res/drawable-hdpi/perm_group_wallpaper.png
+++ b/core/res/res/drawable-hdpi/perm_group_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/popup_background_qntm_mult.9.png b/core/res/res/drawable-hdpi/popup_background_mtrl_mult.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/popup_background_qntm_mult.9.png
rename to core/res/res/drawable-hdpi/popup_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/progress_qntm_alpha.9.png b/core/res/res/drawable-hdpi/progress_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/progress_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/progress_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/progress_primary_qntm_alpha.9.png b/core/res/res/drawable-hdpi/progress_primary_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/progress_primary_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/progress_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrollbar_handle_qntm_alpha.9.png b/core/res/res/drawable-hdpi/scrollbar_handle_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrollbar_handle_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/scrollbar_handle_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_000.png
rename to core/res/res/drawable-hdpi/scrubber_control_from_pressed_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_001.png
rename to core/res/res/drawable-hdpi/scrubber_control_from_pressed_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_002.png
rename to core/res/res/drawable-hdpi/scrubber_control_from_pressed_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_003.png
rename to core/res/res/drawable-hdpi/scrubber_control_from_pressed_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_004.png
rename to core/res/res/drawable-hdpi/scrubber_control_from_pressed_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-hdpi/scrubber_control_from_pressed_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_from_pressed_qntm_005.png
rename to core/res/res/drawable-hdpi/scrubber_control_from_pressed_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_off_qntm_alpha.png b/core/res/res/drawable-hdpi/scrubber_control_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_off_qntm_alpha.png
rename to core/res/res/drawable-hdpi/scrubber_control_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_off_pressed_qntm_alpha.png b/core/res/res/drawable-hdpi/scrubber_control_off_pressed_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_off_pressed_qntm_alpha.png
rename to core/res/res/drawable-hdpi/scrubber_control_off_pressed_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_on_qntm_alpha.png b/core/res/res/drawable-hdpi/scrubber_control_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_on_qntm_alpha.png
rename to core/res/res/drawable-hdpi/scrubber_control_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_on_pressed_qntm_alpha.png b/core/res/res/drawable-hdpi/scrubber_control_on_pressed_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_on_pressed_qntm_alpha.png
rename to core/res/res/drawable-hdpi/scrubber_control_on_pressed_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_000.png
rename to core/res/res/drawable-hdpi/scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_001.png
rename to core/res/res/drawable-hdpi/scrubber_control_to_pressed_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_002.png
rename to core/res/res/drawable-hdpi/scrubber_control_to_pressed_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_003.png
rename to core/res/res/drawable-hdpi/scrubber_control_to_pressed_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_004.png
rename to core/res/res/drawable-hdpi/scrubber_control_to_pressed_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-hdpi/scrubber_control_to_pressed_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_control_to_pressed_qntm_005.png
rename to core/res/res/drawable-hdpi/scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_primary_qntm_alpha.9.png b/core/res/res/drawable-hdpi/scrubber_primary_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_primary_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/scrubber_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-hdpi/scrubber_track_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/scrubber_track_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/scrubber_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_blue.9.png b/core/res/res/drawable-hdpi/sim_dark_blue.9.png
new file mode 100755
index 0000000..b991535
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_green.9.png b/core/res/res/drawable-hdpi/sim_dark_green.9.png
new file mode 100755
index 0000000..c8de61d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_orange.9.png b/core/res/res/drawable-hdpi/sim_dark_orange.9.png
new file mode 100755
index 0000000..10347e8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_purple.9.png b/core/res/res/drawable-hdpi/sim_dark_purple.9.png
new file mode 100755
index 0000000..ac4ee01
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_blue.9.png b/core/res/res/drawable-hdpi/sim_light_blue.9.png
new file mode 100755
index 0000000..b2c5581
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_green.9.png b/core/res/res/drawable-hdpi/sim_light_green.9.png
new file mode 100755
index 0000000..4d29c81
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_orange.9.png b/core/res/res/drawable-hdpi/sim_light_orange.9.png
new file mode 100755
index 0000000..68c6c2f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_purple.9.png b/core/res/res/drawable-hdpi/sim_light_purple.9.png
new file mode 100755
index 0000000..4deb8dc
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_qntm_am_alpha.9.png b/core/res/res/drawable-hdpi/spinner_mtrl_am_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/spinner_qntm_am_alpha.9.png
rename to core/res/res/drawable-hdpi/spinner_mtrl_am_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/switch_track_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_indicator_qntm_alpha.9.png b/core/res/res/drawable-hdpi/tab_indicator_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/tab_indicator_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/tab_indicator_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_cursor_qntm_alpha.9.png b/core/res/res/drawable-hdpi/text_cursor_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/text_cursor_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/text_cursor_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_left_qntm_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/text_select_handle_left_qntm_alpha.png
rename to core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_middle_qntm_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_middle_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/text_select_handle_middle_qntm_alpha.png
rename to core/res/res/drawable-hdpi/text_select_handle_middle_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_right_qntm_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-hdpi/text_select_handle_right_qntm_alpha.png
rename to core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_activated_qntm_alpha.9.png b/core/res/res/drawable-hdpi/textfield_activated_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/textfield_activated_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_default_qntm_alpha.9.png b/core/res/res/drawable-hdpi/textfield_default_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/textfield_default_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_activated_qntm_alpha.9.png b/core/res/res/drawable-hdpi/textfield_search_activated_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/textfield_search_activated_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_default_qntm_alpha.9.png b/core/res/res/drawable-hdpi/textfield_search_default_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-hdpi/textfield_search_default_qntm_alpha.9.png
rename to core/res/res/drawable-hdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/work_icon.png b/core/res/res/drawable-hdpi/work_icon.png
deleted file mode 100644
index be8a36e..0000000
--- a/core/res/res/drawable-hdpi/work_icon.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ab_solid_shadow_qntm.9.png b/core/res/res/drawable-ldpi/ab_solid_shadow_mtrl.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ab_solid_shadow_qntm.9.png
rename to core/res/res/drawable-ldpi/ab_solid_shadow_mtrl.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ab_transparent_qntm_alpha.9.png b/core/res/res/drawable-ldpi/ab_transparent_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ab_transparent_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/ab_transparent_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_check_off_qntm_alpha.png b/core/res/res/drawable-ldpi/btn_check_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/btn_check_off_qntm_alpha.png
rename to core/res/res/drawable-ldpi/btn_check_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_check_on_qntm_alpha.png b/core/res/res/drawable-ldpi/btn_check_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/btn_check_on_qntm_alpha.png
rename to core/res/res/drawable-ldpi/btn_check_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_qntm_alpha.9.png b/core/res/res/drawable-ldpi/btn_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/btn_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/btn_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_radio_off_qntm_alpha.png b/core/res/res/drawable-ldpi/btn_radio_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/btn_radio_off_qntm_alpha.png
rename to core/res/res/drawable-ldpi/btn_radio_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_radio_off_pressed_qntm_alpha.png b/core/res/res/drawable-ldpi/btn_radio_off_pressed_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/btn_radio_off_pressed_qntm_alpha.png
rename to core/res/res/drawable-ldpi/btn_radio_off_pressed_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_radio_on_qntm_alpha.png b/core/res/res/drawable-ldpi/btn_radio_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/btn_radio_on_qntm_alpha.png
rename to core/res/res/drawable-ldpi/btn_radio_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_radio_on_pressed_qntm_alpha.png b/core/res/res/drawable-ldpi/btn_radio_on_pressed_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/btn_radio_on_pressed_qntm_alpha.png
rename to core/res/res/drawable-ldpi/btn_radio_on_pressed_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_star_qntm_alpha.png b/core/res/res/drawable-ldpi/btn_star_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/btn_star_qntm_alpha.png
rename to core/res/res/drawable-ldpi/btn_star_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/expander_close_qntm_alpha.9.png b/core/res/res/drawable-ldpi/expander_close_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/expander_close_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/expander_close_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/expander_open_qntm_alpha.9.png b/core/res/res/drawable-ldpi/expander_open_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/expander_open_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/expander_open_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/fastscroll_thumb_qntm_alpha.png b/core/res/res/drawable-ldpi/fastscroll_thumb_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/fastscroll_thumb_qntm_alpha.png
rename to core/res/res/drawable-ldpi/fastscroll_thumb_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/fastscroll_track_qntm_alpha.9.png b/core/res/res/drawable-ldpi/fastscroll_track_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/fastscroll_track_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/fastscroll_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_ab_back_qntm_am_alpha.png b/core/res/res/drawable-ldpi/ic_ab_back_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_ab_back_qntm_am_alpha.png
rename to core/res/res/drawable-ldpi/ic_ab_back_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_cab_done_qntm_alpha.png b/core/res/res/drawable-ldpi/ic_cab_done_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_cab_done_qntm_alpha.png
rename to core/res/res/drawable-ldpi/ic_cab_done_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_dialog_alert_qntm_alpha.png b/core/res/res/drawable-ldpi/ic_dialog_alert_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_dialog_alert_qntm_alpha.png
rename to core/res/res/drawable-ldpi/ic_dialog_alert_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_find_next_qntm_alpha.png b/core/res/res/drawable-ldpi/ic_find_next_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_find_next_qntm_alpha.png
rename to core/res/res/drawable-ldpi/ic_find_next_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_find_previous_qntm_alpha.png b/core/res/res/drawable-ldpi/ic_find_previous_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_find_previous_qntm_alpha.png
rename to core/res/res/drawable-ldpi/ic_find_previous_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_menu_copy_qntm_am_alpha.png b/core/res/res/drawable-ldpi/ic_menu_copy_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_menu_copy_qntm_am_alpha.png
rename to core/res/res/drawable-ldpi/ic_menu_copy_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_menu_cut_qntm_alpha.png b/core/res/res/drawable-ldpi/ic_menu_cut_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_menu_cut_qntm_alpha.png
rename to core/res/res/drawable-ldpi/ic_menu_cut_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_menu_find_qntm_alpha.png b/core/res/res/drawable-ldpi/ic_menu_find_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_menu_find_qntm_alpha.png
rename to core/res/res/drawable-ldpi/ic_menu_find_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_menu_moreoverflow_qntm_alpha.png b/core/res/res/drawable-ldpi/ic_menu_moreoverflow_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_menu_moreoverflow_qntm_alpha.png
rename to core/res/res/drawable-ldpi/ic_menu_moreoverflow_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_menu_paste_qntm_am_alpha.png b/core/res/res/drawable-ldpi/ic_menu_paste_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_menu_paste_qntm_am_alpha.png
rename to core/res/res/drawable-ldpi/ic_menu_paste_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_menu_search_qntm_alpha.png b/core/res/res/drawable-ldpi/ic_menu_search_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_menu_search_qntm_alpha.png
rename to core/res/res/drawable-ldpi/ic_menu_search_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_menu_selectall_qntm_alpha.png b/core/res/res/drawable-ldpi/ic_menu_selectall_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_menu_selectall_qntm_alpha.png
rename to core/res/res/drawable-ldpi/ic_menu_selectall_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_menu_share_qntm_alpha.png b/core/res/res/drawable-ldpi/ic_menu_share_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/ic_menu_share_qntm_alpha.png
rename to core/res/res/drawable-ldpi/ic_menu_share_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/list_divider_qntm_alpha.9.png b/core/res/res/drawable-ldpi/list_divider_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/list_divider_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/list_divider_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/list_section_divider_qntm_alpha.9.png b/core/res/res/drawable-ldpi/list_section_divider_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/list_section_divider_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/list_section_divider_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/progress_qntm_alpha.9.png b/core/res/res/drawable-ldpi/progress_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/progress_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/progress_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/progress_primary_qntm_alpha.9.png b/core/res/res/drawable-ldpi/progress_primary_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/progress_primary_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/progress_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/scrollbar_handle_qntm_alpha.9.png b/core/res/res/drawable-ldpi/scrollbar_handle_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/scrollbar_handle_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/scrollbar_handle_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/scrubber_control_off_qntm_alpha.png b/core/res/res/drawable-ldpi/scrubber_control_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/scrubber_control_off_qntm_alpha.png
rename to core/res/res/drawable-ldpi/scrubber_control_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/scrubber_control_off_pressed_qntm_alpha.png b/core/res/res/drawable-ldpi/scrubber_control_off_pressed_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/scrubber_control_off_pressed_qntm_alpha.png
rename to core/res/res/drawable-ldpi/scrubber_control_off_pressed_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/scrubber_control_on_qntm_alpha.png b/core/res/res/drawable-ldpi/scrubber_control_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-ldpi/scrubber_control_on_qntm_alpha.png
rename to core/res/res/drawable-ldpi/scrubber_control_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/btn_radio_on_pressed_qntm_alpha.png b/core/res/res/drawable-ldpi/scrubber_control_on_pressed_mtrl_alpha.png
similarity index 100%
copy from core/res/res/drawable-ldpi/btn_radio_on_pressed_qntm_alpha.png
copy to core/res/res/drawable-ldpi/scrubber_control_on_pressed_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/scrubber_control_on_pressed_qntm_alpha.png b/core/res/res/drawable-ldpi/scrubber_control_on_pressed_qntm_alpha.png
deleted file mode 100644
index 458abaf..0000000
--- a/core/res/res/drawable-ldpi/scrubber_control_on_pressed_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/scrubber_primary_qntm_alpha.9.png b/core/res/res/drawable-ldpi/scrubber_primary_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/scrubber_primary_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/scrubber_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/spinner_qntm_am_alpha.9.png b/core/res/res/drawable-ldpi/spinner_mtrl_am_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/spinner_qntm_am_alpha.9.png
rename to core/res/res/drawable-ldpi/spinner_mtrl_am_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/switch_off_qntm_alpha.9.png b/core/res/res/drawable-ldpi/switch_off_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/switch_off_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/switch_off_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/switch_on_qntm_alpha.9.png b/core/res/res/drawable-ldpi/switch_on_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/switch_on_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/switch_on_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/progress_qntm_alpha.9.png b/core/res/res/drawable-ldpi/switch_track_mtrl_alpha.9.png
similarity index 100%
copy from core/res/res/drawable-ldpi/progress_qntm_alpha.9.png
copy to core/res/res/drawable-ldpi/switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-ldpi/switch_track_qntm_alpha.9.png
deleted file mode 100644
index a58128f..0000000
--- a/core/res/res/drawable-ldpi/switch_track_qntm_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/text_cursor_qntm_alpha.9.png b/core/res/res/drawable-ldpi/text_cursor_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/text_cursor_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/text_cursor_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/textfield_activated_qntm_alpha.9.png b/core/res/res/drawable-ldpi/textfield_activated_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/textfield_activated_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/textfield_default_qntm_alpha.9.png b/core/res/res/drawable-ldpi/textfield_default_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-ldpi/textfield_default_qntm_alpha.9.png
rename to core/res/res/drawable-ldpi/textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_share_pack_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_share_pack_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ab_share_pack_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/ab_share_pack_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ab_solid_shadow_qntm_alpha.9.png b/core/res/res/drawable-mdpi/ab_solid_shadow_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ab_solid_shadow_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/ab_solid_shadow_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_cab_done_qntm_alpha.9.png b/core/res/res/drawable-mdpi/btn_cab_done_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_cab_done_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/btn_cab_done_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_000.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_001.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_002.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_003.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_004.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_005.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_006.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_007.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_008.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_009.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_010.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_011.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_012.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_013.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_014.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_off_qntm_015.png
rename to core/res/res/drawable-mdpi/btn_check_to_off_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_000.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_001.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_002.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_003.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_004.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_005.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_006.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_007.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_008.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_009.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_010.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_011.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_012.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_013.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_014.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_check_to_on_qntm_015.png
rename to core/res/res/drawable-mdpi/btn_check_to_on_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_code_lock_default_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_code_lock_default_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_code_lock_default_qntm_alpha.png
rename to core/res/res/drawable-mdpi/btn_code_lock_default_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_code_lock_touched_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_code_lock_touched_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_code_lock_touched_qntm_alpha.png
rename to core/res/res/drawable-mdpi/btn_code_lock_touched_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_qntm_alpha.9.png b/core/res/res/drawable-mdpi/btn_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/btn_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_on_qntm_alpha.png
rename to core/res/res/drawable-mdpi/btn_radio_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_on_pressed_qntm_alpha.png
rename to core/res/res/drawable-mdpi/btn_radio_on_pressed_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_000.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_001.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_002.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_003.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_004.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_005.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_006.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_007.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_008.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_009.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_010.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_011.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_012.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_013.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_014.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_off_qntm_015.png
rename to core/res/res/drawable-mdpi/btn_radio_to_off_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_000.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_001.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_002.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_003.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_004.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_005.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_006.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_007.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_008.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_009.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_010.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_011.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_012.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_013.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_014.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_radio_to_on_qntm_015.png
rename to core/res/res/drawable-mdpi/btn_radio_to_on_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_rating_star_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_rating_star_off_qntm_alpha.png
rename to core/res/res/drawable-mdpi/btn_rating_star_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_rating_star_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_rating_star_on_qntm_alpha.png
rename to core/res/res/drawable-mdpi/btn_rating_star_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_star_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_star_qntm_alpha.png
rename to core/res/res/drawable-mdpi/btn_star_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_000.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_001.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_002.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_003.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_004.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_005.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_006.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_007.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_008.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_009.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_010.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_011.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_012.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_013.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_off_qntm_014.png
rename to core/res/res/drawable-mdpi/btn_switch_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_000.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_001.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_002.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_003.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_004.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_005.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_006.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_007.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_008.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_009.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_010.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_011.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_012.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_013.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_switch_to_on_qntm_014.png
rename to core/res/res/drawable-mdpi/btn_switch_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-mdpi/btn_toggle_indicator_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_toggle_indicator_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/btn_toggle_indicator_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-mdpi/btn_toggle_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/btn_toggle_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/btn_toggle_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
index 3fdd3bc..4e6d076 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png
index 3fdd3bc..4e6d076 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png
index eaa02b3..ca61cb2 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png
index eaa02b3..ca61cb2 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png
index 28c8b94..b5999be 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png
index 28c8b94..b5999be 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png
index 6090cce..8392ac3 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png
index 6090cce..522bafd 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
index 3f2e982..ebb2f8b 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png
index 3f2e982..ebb2f8b 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png
index 14b958b..3fa20ca 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png
index 14b958b..3fa20ca 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png
index 4db22d4..6cc59ed 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png
index 4db22d4..6cc59ed 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png
index a11e1c7..a1fcd08 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png
index a11e1c7..c6c0224 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_background_mtrl_mult.9.png b/core/res/res/drawable-mdpi/dialog_background_mtrl_mult.9.png
new file mode 100644
index 0000000..8322ae3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/expander_close_qntm_alpha.9.png b/core/res/res/drawable-mdpi/expander_close_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/expander_close_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/expander_close_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/expander_open_qntm_alpha.9.png b/core/res/res/drawable-mdpi/expander_open_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/expander_open_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/expander_open_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/fastscroll_thumb_qntm_alpha.png b/core/res/res/drawable-mdpi/fastscroll_thumb_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/fastscroll_thumb_qntm_alpha.png
rename to core/res/res/drawable-mdpi/fastscroll_thumb_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/fastscroll_track_qntm_alpha.9.png b/core/res/res/drawable-mdpi/fastscroll_track_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/fastscroll_track_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/fastscroll_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_ab_back_qntm_am_alpha.png b/core/res/res/drawable-mdpi/ic_ab_back_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_ab_back_qntm_am_alpha.png
rename to core/res/res/drawable-mdpi/ic_ab_back_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_afw_icon.png b/core/res/res/drawable-mdpi/ic_afw_icon.png
new file mode 100644
index 0000000..deb7966
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_afw_icon.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_cab_done_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_cab_done_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_cab_done_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_cab_done_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_clear_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_clear_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_clear_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_clear_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_commit_search_api_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_commit_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_commit_search_api_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_commit_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_dialog_alert_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_dialog_alert_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_dialog_alert_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_dialog_alert_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_find_next_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_find_next_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_find_next_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_find_next_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_find_previous_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_find_previous_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_find_previous_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_find_previous_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_go_search_api_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_go_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_go_search_api_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_go_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_disabled_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_disabled_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_media_route_disabled_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_media_route_disabled_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_off_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_media_route_off_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_media_route_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_0_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_on_0_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_media_route_on_0_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_media_route_on_0_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_1_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_on_1_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_media_route_on_1_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_media_route_on_1_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_2_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_on_2_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_media_route_on_2_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_media_route_on_2_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_media_route_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_media_route_on_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_media_route_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_copy_qntm_am_alpha.png b/core/res/res/drawable-mdpi/ic_menu_copy_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_copy_qntm_am_alpha.png
rename to core/res/res/drawable-mdpi/ic_menu_copy_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_cut_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_menu_cut_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_cut_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_menu_cut_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_find_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_menu_find_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_find_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_menu_find_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_moreoverflow_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_menu_moreoverflow_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_moreoverflow_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_menu_moreoverflow_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_paste_qntm_am_alpha.png b/core/res/res/drawable-mdpi/ic_menu_paste_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_paste_qntm_am_alpha.png
rename to core/res/res/drawable-mdpi/ic_menu_paste_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_search_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_menu_search_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_search_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_menu_search_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_selectall_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_menu_selectall_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_selectall_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_menu_selectall_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_menu_share_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_menu_share_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_menu_share_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_menu_share_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_search_api_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_search_api_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_voice_search_api_qntm_alpha.png b/core/res/res/drawable-mdpi/ic_voice_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/ic_voice_search_api_qntm_alpha.png
rename to core/res/res/drawable-mdpi/ic_voice_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_up_qntm_alpha.png b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_up_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_up_qntm_alpha.png
rename to core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_up_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default_qntm_alpha.png b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_default_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/indicator_code_lock_point_area_default_qntm_alpha.png
rename to core/res/res/drawable-mdpi/indicator_code_lock_point_area_default_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_qntm_alpha.png b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/indicator_code_lock_point_area_qntm_alpha.png
rename to core/res/res/drawable-mdpi/indicator_code_lock_point_area_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_divider_qntm_alpha.9.png b/core/res/res/drawable-mdpi/list_divider_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/list_divider_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/list_divider_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_section_divider_qntm_alpha.9.png b/core/res/res/drawable-mdpi/list_section_divider_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/list_section_divider_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/list_section_divider_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_accessibility_features.png b/core/res/res/drawable-mdpi/perm_group_accessibility_features.png
index df5c147..57c4167 100644
--- a/core/res/res/drawable-mdpi/perm_group_accessibility_features.png
+++ b/core/res/res/drawable-mdpi/perm_group_accessibility_features.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_accounts.png b/core/res/res/drawable-mdpi/perm_group_accounts.png
index 0c4dd02..ce4e683 100644
--- a/core/res/res/drawable-mdpi/perm_group_accounts.png
+++ b/core/res/res/drawable-mdpi/perm_group_accounts.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_affects_battery.png b/core/res/res/drawable-mdpi/perm_group_affects_battery.png
index 511921d..55a0b79 100644
--- a/core/res/res/drawable-mdpi/perm_group_affects_battery.png
+++ b/core/res/res/drawable-mdpi/perm_group_affects_battery.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_app_info.png b/core/res/res/drawable-mdpi/perm_group_app_info.png
index e715177..8393586 100644
--- a/core/res/res/drawable-mdpi/perm_group_app_info.png
+++ b/core/res/res/drawable-mdpi/perm_group_app_info.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_audio_settings.png b/core/res/res/drawable-mdpi/perm_group_audio_settings.png
index 26ff28e..734429f 100644
--- a/core/res/res/drawable-mdpi/perm_group_audio_settings.png
+++ b/core/res/res/drawable-mdpi/perm_group_audio_settings.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_bluetooth.png b/core/res/res/drawable-mdpi/perm_group_bluetooth.png
index effa405..4b79c1a 100644
--- a/core/res/res/drawable-mdpi/perm_group_bluetooth.png
+++ b/core/res/res/drawable-mdpi/perm_group_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_bookmarks.png b/core/res/res/drawable-mdpi/perm_group_bookmarks.png
index 2103632..ca3d453 100644
--- a/core/res/res/drawable-mdpi/perm_group_bookmarks.png
+++ b/core/res/res/drawable-mdpi/perm_group_bookmarks.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_calendar.png b/core/res/res/drawable-mdpi/perm_group_calendar.png
index e22fd7f..d2ad9d6 100644
--- a/core/res/res/drawable-mdpi/perm_group_calendar.png
+++ b/core/res/res/drawable-mdpi/perm_group_calendar.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_camera.png b/core/res/res/drawable-mdpi/perm_group_camera.png
index 463654b..1727cf1 100644
--- a/core/res/res/drawable-mdpi/perm_group_camera.png
+++ b/core/res/res/drawable-mdpi/perm_group_camera.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_device_alarms.png b/core/res/res/drawable-mdpi/perm_group_device_alarms.png
index 1348131..48339cd 100644
--- a/core/res/res/drawable-mdpi/perm_group_device_alarms.png
+++ b/core/res/res/drawable-mdpi/perm_group_device_alarms.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_display.png b/core/res/res/drawable-mdpi/perm_group_display.png
index ea51240..9738f15 100644
--- a/core/res/res/drawable-mdpi/perm_group_display.png
+++ b/core/res/res/drawable-mdpi/perm_group_display.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_location.png b/core/res/res/drawable-mdpi/perm_group_location.png
index 2fcb124..7ad1e02 100644
--- a/core/res/res/drawable-mdpi/perm_group_location.png
+++ b/core/res/res/drawable-mdpi/perm_group_location.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_messages.png b/core/res/res/drawable-mdpi/perm_group_messages.png
index 6f3ecf8..12c5d88 100644
--- a/core/res/res/drawable-mdpi/perm_group_messages.png
+++ b/core/res/res/drawable-mdpi/perm_group_messages.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_microphone.png b/core/res/res/drawable-mdpi/perm_group_microphone.png
index b4717a3..f6015b5 100644
--- a/core/res/res/drawable-mdpi/perm_group_microphone.png
+++ b/core/res/res/drawable-mdpi/perm_group_microphone.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_network.png b/core/res/res/drawable-mdpi/perm_group_network.png
index a624e42..c575d70 100644
--- a/core/res/res/drawable-mdpi/perm_group_network.png
+++ b/core/res/res/drawable-mdpi/perm_group_network.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_personal_info.png b/core/res/res/drawable-mdpi/perm_group_personal_info.png
index cf56fa50..13ec27e 100644
--- a/core/res/res/drawable-mdpi/perm_group_personal_info.png
+++ b/core/res/res/drawable-mdpi/perm_group_personal_info.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_phone_calls.png b/core/res/res/drawable-mdpi/perm_group_phone_calls.png
index 467f37f..e373c2c 100644
--- a/core/res/res/drawable-mdpi/perm_group_phone_calls.png
+++ b/core/res/res/drawable-mdpi/perm_group_phone_calls.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_screenlock.png b/core/res/res/drawable-mdpi/perm_group_screenlock.png
index f8b351e..9d9bb75 100644
--- a/core/res/res/drawable-mdpi/perm_group_screenlock.png
+++ b/core/res/res/drawable-mdpi/perm_group_screenlock.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_shortrange_network.png b/core/res/res/drawable-mdpi/perm_group_shortrange_network.png
index a624e42..5d35676 100644
--- a/core/res/res/drawable-mdpi/perm_group_shortrange_network.png
+++ b/core/res/res/drawable-mdpi/perm_group_shortrange_network.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_social_info.png b/core/res/res/drawable-mdpi/perm_group_social_info.png
index 8ae10f1..4ca0767 100644
--- a/core/res/res/drawable-mdpi/perm_group_social_info.png
+++ b/core/res/res/drawable-mdpi/perm_group_social_info.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_status_bar.png b/core/res/res/drawable-mdpi/perm_group_status_bar.png
index 86868ab..f10536b 100644
--- a/core/res/res/drawable-mdpi/perm_group_status_bar.png
+++ b/core/res/res/drawable-mdpi/perm_group_status_bar.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_storage.png b/core/res/res/drawable-mdpi/perm_group_storage.png
index 61ff8a3..b7a06fb 100644
--- a/core/res/res/drawable-mdpi/perm_group_storage.png
+++ b/core/res/res/drawable-mdpi/perm_group_storage.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_sync_settings.png b/core/res/res/drawable-mdpi/perm_group_sync_settings.png
index 9049f47..f5ef82b 100644
--- a/core/res/res/drawable-mdpi/perm_group_sync_settings.png
+++ b/core/res/res/drawable-mdpi/perm_group_sync_settings.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_system_clock.png b/core/res/res/drawable-mdpi/perm_group_system_clock.png
index 554dd0f..3a67642 100644
--- a/core/res/res/drawable-mdpi/perm_group_system_clock.png
+++ b/core/res/res/drawable-mdpi/perm_group_system_clock.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_system_tools.png b/core/res/res/drawable-mdpi/perm_group_system_tools.png
index 845a593..fd282e6 100644
--- a/core/res/res/drawable-mdpi/perm_group_system_tools.png
+++ b/core/res/res/drawable-mdpi/perm_group_system_tools.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_user_dictionary.png b/core/res/res/drawable-mdpi/perm_group_user_dictionary.png
index 188343d..a303dc1 100644
--- a/core/res/res/drawable-mdpi/perm_group_user_dictionary.png
+++ b/core/res/res/drawable-mdpi/perm_group_user_dictionary.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_user_dictionary_write.png b/core/res/res/drawable-mdpi/perm_group_user_dictionary_write.png
index 04b9cdc..2fc4056 100644
--- a/core/res/res/drawable-mdpi/perm_group_user_dictionary_write.png
+++ b/core/res/res/drawable-mdpi/perm_group_user_dictionary_write.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_voicemail.png b/core/res/res/drawable-mdpi/perm_group_voicemail.png
index 163046b..108a725 100644
--- a/core/res/res/drawable-mdpi/perm_group_voicemail.png
+++ b/core/res/res/drawable-mdpi/perm_group_voicemail.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/perm_group_wallpaper.png b/core/res/res/drawable-mdpi/perm_group_wallpaper.png
index 5b96e08..aa06f38 100644
--- a/core/res/res/drawable-mdpi/perm_group_wallpaper.png
+++ b/core/res/res/drawable-mdpi/perm_group_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/popup_background_qntm_mult.9.png b/core/res/res/drawable-mdpi/popup_background_mtrl_mult.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/popup_background_qntm_mult.9.png
rename to core/res/res/drawable-mdpi/popup_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/progress_qntm_alpha.9.png b/core/res/res/drawable-mdpi/progress_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/progress_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/progress_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/progress_primary_qntm_alpha.9.png b/core/res/res/drawable-mdpi/progress_primary_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/progress_primary_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/progress_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrollbar_handle_qntm_alpha.9.png b/core/res/res/drawable-mdpi/scrollbar_handle_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrollbar_handle_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/scrollbar_handle_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_000.png
rename to core/res/res/drawable-mdpi/scrubber_control_from_pressed_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_001.png
rename to core/res/res/drawable-mdpi/scrubber_control_from_pressed_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_002.png
rename to core/res/res/drawable-mdpi/scrubber_control_from_pressed_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_003.png
rename to core/res/res/drawable-mdpi/scrubber_control_from_pressed_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_004.png
rename to core/res/res/drawable-mdpi/scrubber_control_from_pressed_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-mdpi/scrubber_control_from_pressed_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_from_pressed_qntm_005.png
rename to core/res/res/drawable-mdpi/scrubber_control_from_pressed_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_off_qntm_alpha.png b/core/res/res/drawable-mdpi/scrubber_control_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_off_qntm_alpha.png
rename to core/res/res/drawable-mdpi/scrubber_control_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_off_pressed_qntm_alpha.png b/core/res/res/drawable-mdpi/scrubber_control_off_pressed_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_off_pressed_qntm_alpha.png
rename to core/res/res/drawable-mdpi/scrubber_control_off_pressed_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_on_qntm_alpha.png b/core/res/res/drawable-mdpi/scrubber_control_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_on_qntm_alpha.png
rename to core/res/res/drawable-mdpi/scrubber_control_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed_qntm_alpha.png b/core/res/res/drawable-mdpi/scrubber_control_on_pressed_mtrl_alpha.png
similarity index 100%
copy from core/res/res/drawable-mdpi/btn_radio_on_pressed_qntm_alpha.png
copy to core/res/res/drawable-mdpi/scrubber_control_on_pressed_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_on_pressed_qntm_alpha.png b/core/res/res/drawable-mdpi/scrubber_control_on_pressed_qntm_alpha.png
deleted file mode 100644
index 3c304bf..0000000
--- a/core/res/res/drawable-mdpi/scrubber_control_on_pressed_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_000.png
rename to core/res/res/drawable-mdpi/scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_001.png
rename to core/res/res/drawable-mdpi/scrubber_control_to_pressed_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_002.png
rename to core/res/res/drawable-mdpi/scrubber_control_to_pressed_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_003.png
rename to core/res/res/drawable-mdpi/scrubber_control_to_pressed_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_004.png
rename to core/res/res/drawable-mdpi/scrubber_control_to_pressed_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-mdpi/scrubber_control_to_pressed_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_control_to_pressed_qntm_005.png
rename to core/res/res/drawable-mdpi/scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_primary_qntm_alpha.9.png b/core/res/res/drawable-mdpi/scrubber_primary_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_primary_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/scrubber_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-mdpi/scrubber_track_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/scrubber_track_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/scrubber_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_blue.9.png b/core/res/res/drawable-mdpi/sim_dark_blue.9.png
new file mode 100755
index 0000000..d646a7f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_green.9.png b/core/res/res/drawable-mdpi/sim_dark_green.9.png
new file mode 100755
index 0000000..ee4ea0d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_orange.9.png b/core/res/res/drawable-mdpi/sim_dark_orange.9.png
new file mode 100755
index 0000000..b394999
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_purple.9.png b/core/res/res/drawable-mdpi/sim_dark_purple.9.png
new file mode 100755
index 0000000..459b5d69
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_blue.9.png b/core/res/res/drawable-mdpi/sim_light_blue.9.png
new file mode 100755
index 0000000..396ad70
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_green.9.png b/core/res/res/drawable-mdpi/sim_light_green.9.png
new file mode 100755
index 0000000..a063174
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_orange.9.png b/core/res/res/drawable-mdpi/sim_light_orange.9.png
new file mode 100755
index 0000000..95ea88e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_purple.9.png b/core/res/res/drawable-mdpi/sim_light_purple.9.png
new file mode 100755
index 0000000..b1bd35f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_qntm_am_alpha.9.png b/core/res/res/drawable-mdpi/spinner_mtrl_am_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/spinner_qntm_am_alpha.9.png
rename to core/res/res/drawable-mdpi/spinner_mtrl_am_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/switch_track_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_indicator_qntm_alpha.9.png b/core/res/res/drawable-mdpi/tab_indicator_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/tab_indicator_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/tab_indicator_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_cursor_qntm_alpha.9.png b/core/res/res/drawable-mdpi/text_cursor_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/text_cursor_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/text_cursor_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_left_qntm_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/text_select_handle_left_qntm_alpha.png
rename to core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_middle_qntm_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_middle_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/text_select_handle_middle_qntm_alpha.png
rename to core/res/res/drawable-mdpi/text_select_handle_middle_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_right_qntm_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-mdpi/text_select_handle_right_qntm_alpha.png
rename to core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_activated_qntm_alpha.9.png b/core/res/res/drawable-mdpi/textfield_activated_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/textfield_activated_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_default_qntm_alpha.9.png b/core/res/res/drawable-mdpi/textfield_default_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/textfield_default_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_activated_qntm_alpha.9.png b/core/res/res/drawable-mdpi/textfield_search_activated_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/textfield_search_activated_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_default_qntm_alpha.9.png b/core/res/res/drawable-mdpi/textfield_search_default_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-mdpi/textfield_search_default_qntm_alpha.9.png
rename to core/res/res/drawable-mdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_share_pack_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_share_pack_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ab_share_pack_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/ab_share_pack_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ab_solid_shadow_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/ab_solid_shadow_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ab_solid_shadow_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/ab_solid_shadow_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_cab_done_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/btn_cab_done_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_cab_done_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/btn_cab_done_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_000.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_001.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_002.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_003.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_004.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_005.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_006.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_007.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_008.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_009.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_010.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_011.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_012.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_013.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_014.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_off_qntm_015.png
rename to core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_000.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_001.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_002.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_003.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_004.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_005.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_006.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_007.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_008.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_009.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_010.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_011.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_012.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_013.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_014.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_check_to_on_qntm_015.png
rename to core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_code_lock_default_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_code_lock_default_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_code_lock_default_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/btn_code_lock_default_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_code_lock_touched_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_code_lock_touched_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_code_lock_touched_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/btn_code_lock_touched_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/btn_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/btn_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_on_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_on_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/btn_radio_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_on_pressed_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/btn_radio_on_pressed_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_000.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_001.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_002.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_003.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_004.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_005.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_006.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_007.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_008.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_009.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_010.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_011.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_012.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_013.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_014.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_off_qntm_015.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_off_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_000.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_001.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_002.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_003.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_004.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_005.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_006.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_007.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_008.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_009.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_010.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_011.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_012.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_013.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_014.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_radio_to_on_qntm_015.png
rename to core/res/res/drawable-xhdpi/btn_radio_to_on_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_rating_star_off_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/btn_rating_star_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_rating_star_on_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/btn_rating_star_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_star_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_star_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/btn_star_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_000.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_001.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_002.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_003.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_004.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_005.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_006.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_007.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_008.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_009.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_010.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_011.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_012.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_013.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_off_qntm_014.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_000.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_001.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_002.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_003.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_004.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_005.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_006.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_007.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_008.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_009.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_010.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_011.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_012.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_013.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_switch_to_on_qntm_014.png
rename to core/res/res/drawable-xhdpi/btn_switch_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/btn_toggle_indicator_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_toggle_indicator_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/btn_toggle_indicator_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/btn_toggle_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/btn_toggle_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/btn_toggle_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
index c08deab..1e45530 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_light.9.png
index c08deab..1e45530 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_dark.9.png
index 8b1a55c..2c63c5d 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_light.9.png
index 8b1a55c..2c63c5d 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_dark.9.png
index 77cd1fa..dd5e26e 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_light.9.png
index 77cd1fa..dd5e26e 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_dark.9.png
index e0e3540..aa9b3c5 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_light.9.png
index e0e3540..367c25a 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
index 324e490..df28ad0 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_light.9.png
index 324e490..df28ad0 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_dark.9.png
index e126cc6..3a27831 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_light.9.png
index e126cc6..3a27831 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_dark.9.png
index 4c1f1b9..d68bdf4 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_light.9.png
index 4c1f1b9..d68bdf4 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_dark.9.png
index 219d37b..da03ec9 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_light.9.png
index 219d37b..482b249 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_background_mtrl_mult.9.png b/core/res/res/drawable-xhdpi/dialog_background_mtrl_mult.9.png
new file mode 100644
index 0000000..e6c0047
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/expander_close_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/expander_close_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/expander_close_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/expander_close_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/expander_open_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/expander_open_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/expander_open_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/expander_open_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/fastscroll_thumb_qntm_alpha.png b/core/res/res/drawable-xhdpi/fastscroll_thumb_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/fastscroll_thumb_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/fastscroll_thumb_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/fastscroll_track_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/fastscroll_track_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/fastscroll_track_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/fastscroll_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_ab_back_qntm_am_alpha.png b/core/res/res/drawable-xhdpi/ic_ab_back_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_ab_back_qntm_am_alpha.png
rename to core/res/res/drawable-xhdpi/ic_ab_back_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_afw_icon.png b/core/res/res/drawable-xhdpi/ic_afw_icon.png
new file mode 100644
index 0000000..ec4f44b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_afw_icon.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_cab_done_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_cab_done_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_cab_done_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_cab_done_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_clear_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_clear_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_clear_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_clear_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_commit_search_api_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_commit_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_commit_search_api_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_commit_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_dialog_alert_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_dialog_alert_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_dialog_alert_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_dialog_alert_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_find_next_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_find_next_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_find_next_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_find_next_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_find_previous_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_find_previous_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_find_previous_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_find_previous_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_go_search_api_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_go_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_go_search_api_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_go_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_disabled_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_disabled_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_media_route_disabled_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_media_route_disabled_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_off_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_media_route_off_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_media_route_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_0_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_on_0_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_media_route_on_0_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_media_route_on_0_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_1_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_on_1_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_media_route_on_1_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_media_route_on_1_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_2_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_on_2_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_media_route_on_2_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_media_route_on_2_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_media_route_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_media_route_on_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_media_route_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_copy_qntm_am_alpha.png b/core/res/res/drawable-xhdpi/ic_menu_copy_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_menu_copy_qntm_am_alpha.png
rename to core/res/res/drawable-xhdpi/ic_menu_copy_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_cut_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_menu_cut_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_menu_cut_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_menu_cut_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_find_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_menu_find_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_menu_find_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_menu_find_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_moreoverflow_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_menu_moreoverflow_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_menu_moreoverflow_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_menu_moreoverflow_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_paste_qntm_am_alpha.png b/core/res/res/drawable-xhdpi/ic_menu_paste_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_menu_paste_qntm_am_alpha.png
rename to core/res/res/drawable-xhdpi/ic_menu_paste_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_search_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_menu_search_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_menu_search_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_menu_search_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_selectall_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_menu_selectall_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_menu_selectall_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_menu_selectall_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_menu_share_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_menu_share_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_menu_share_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_menu_share_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_search_api_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_search_api_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_voice_search_api_qntm_alpha.png b/core/res/res/drawable-xhdpi/ic_voice_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/ic_voice_search_api_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/ic_voice_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/indicator_code_lock_drag_direction_up_qntm_alpha.png b/core/res/res/drawable-xhdpi/indicator_code_lock_drag_direction_up_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/indicator_code_lock_drag_direction_up_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/indicator_code_lock_drag_direction_up_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_default_qntm_alpha.png b/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_default_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/indicator_code_lock_point_area_default_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/indicator_code_lock_point_area_default_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_qntm_alpha.png b/core/res/res/drawable-xhdpi/indicator_code_lock_point_area_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/indicator_code_lock_point_area_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/indicator_code_lock_point_area_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_divider_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/list_divider_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/list_divider_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/list_divider_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_section_divider_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/list_section_divider_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/list_section_divider_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/list_section_divider_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_accessibility_features.png b/core/res/res/drawable-xhdpi/perm_group_accessibility_features.png
index 9edbada..53a12a1 100644
--- a/core/res/res/drawable-xhdpi/perm_group_accessibility_features.png
+++ b/core/res/res/drawable-xhdpi/perm_group_accessibility_features.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_accounts.png b/core/res/res/drawable-xhdpi/perm_group_accounts.png
index b2cad91..ca622e9 100644
--- a/core/res/res/drawable-xhdpi/perm_group_accounts.png
+++ b/core/res/res/drawable-xhdpi/perm_group_accounts.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_affects_battery.png b/core/res/res/drawable-xhdpi/perm_group_affects_battery.png
index 123e0a2..3527aa7 100644
--- a/core/res/res/drawable-xhdpi/perm_group_affects_battery.png
+++ b/core/res/res/drawable-xhdpi/perm_group_affects_battery.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_app_info.png b/core/res/res/drawable-xhdpi/perm_group_app_info.png
index 8373633..902b795 100644
--- a/core/res/res/drawable-xhdpi/perm_group_app_info.png
+++ b/core/res/res/drawable-xhdpi/perm_group_app_info.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_audio_settings.png b/core/res/res/drawable-xhdpi/perm_group_audio_settings.png
index 7c10395..8100212 100644
--- a/core/res/res/drawable-xhdpi/perm_group_audio_settings.png
+++ b/core/res/res/drawable-xhdpi/perm_group_audio_settings.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_bluetooth.png b/core/res/res/drawable-xhdpi/perm_group_bluetooth.png
index ce58d66..754da87 100644
--- a/core/res/res/drawable-xhdpi/perm_group_bluetooth.png
+++ b/core/res/res/drawable-xhdpi/perm_group_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_bookmarks.png b/core/res/res/drawable-xhdpi/perm_group_bookmarks.png
index db28d89..44525bc 100644
--- a/core/res/res/drawable-xhdpi/perm_group_bookmarks.png
+++ b/core/res/res/drawable-xhdpi/perm_group_bookmarks.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_calendar.png b/core/res/res/drawable-xhdpi/perm_group_calendar.png
index d49b883..9821c27 100644
--- a/core/res/res/drawable-xhdpi/perm_group_calendar.png
+++ b/core/res/res/drawable-xhdpi/perm_group_calendar.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_camera.png b/core/res/res/drawable-xhdpi/perm_group_camera.png
index 5287e00..23b7167 100644
--- a/core/res/res/drawable-xhdpi/perm_group_camera.png
+++ b/core/res/res/drawable-xhdpi/perm_group_camera.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_device_alarms.png b/core/res/res/drawable-xhdpi/perm_group_device_alarms.png
index c52148d..615578e 100644
--- a/core/res/res/drawable-xhdpi/perm_group_device_alarms.png
+++ b/core/res/res/drawable-xhdpi/perm_group_device_alarms.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_display.png b/core/res/res/drawable-xhdpi/perm_group_display.png
index 90fcc73..1489213 100644
--- a/core/res/res/drawable-xhdpi/perm_group_display.png
+++ b/core/res/res/drawable-xhdpi/perm_group_display.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_location.png b/core/res/res/drawable-xhdpi/perm_group_location.png
index 99dbcbc..d949cdb 100644
--- a/core/res/res/drawable-xhdpi/perm_group_location.png
+++ b/core/res/res/drawable-xhdpi/perm_group_location.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_messages.png b/core/res/res/drawable-xhdpi/perm_group_messages.png
index c674d54..dbb9aba 100644
--- a/core/res/res/drawable-xhdpi/perm_group_messages.png
+++ b/core/res/res/drawable-xhdpi/perm_group_messages.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_microphone.png b/core/res/res/drawable-xhdpi/perm_group_microphone.png
index 9c2a6b6..8887a41 100644
--- a/core/res/res/drawable-xhdpi/perm_group_microphone.png
+++ b/core/res/res/drawable-xhdpi/perm_group_microphone.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_network.png b/core/res/res/drawable-xhdpi/perm_group_network.png
index 8557889..ebe034f 100644
--- a/core/res/res/drawable-xhdpi/perm_group_network.png
+++ b/core/res/res/drawable-xhdpi/perm_group_network.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_personal_info.png b/core/res/res/drawable-xhdpi/perm_group_personal_info.png
index 3a1419a..5ae4111 100644
--- a/core/res/res/drawable-xhdpi/perm_group_personal_info.png
+++ b/core/res/res/drawable-xhdpi/perm_group_personal_info.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_phone_calls.png b/core/res/res/drawable-xhdpi/perm_group_phone_calls.png
index 9a24905..9e1d2ca 100644
--- a/core/res/res/drawable-xhdpi/perm_group_phone_calls.png
+++ b/core/res/res/drawable-xhdpi/perm_group_phone_calls.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_screenlock.png b/core/res/res/drawable-xhdpi/perm_group_screenlock.png
index 49f526e..96d6873 100644
--- a/core/res/res/drawable-xhdpi/perm_group_screenlock.png
+++ b/core/res/res/drawable-xhdpi/perm_group_screenlock.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_shortrange_network.png b/core/res/res/drawable-xhdpi/perm_group_shortrange_network.png
index 8557889..2f0c2d9 100644
--- a/core/res/res/drawable-xhdpi/perm_group_shortrange_network.png
+++ b/core/res/res/drawable-xhdpi/perm_group_shortrange_network.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_social_info.png b/core/res/res/drawable-xhdpi/perm_group_social_info.png
index 1ecda40..842662c 100644
--- a/core/res/res/drawable-xhdpi/perm_group_social_info.png
+++ b/core/res/res/drawable-xhdpi/perm_group_social_info.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_status_bar.png b/core/res/res/drawable-xhdpi/perm_group_status_bar.png
index 19a611b..8103320 100644
--- a/core/res/res/drawable-xhdpi/perm_group_status_bar.png
+++ b/core/res/res/drawable-xhdpi/perm_group_status_bar.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_storage.png b/core/res/res/drawable-xhdpi/perm_group_storage.png
index 85753f1..a2d4d5e 100644
--- a/core/res/res/drawable-xhdpi/perm_group_storage.png
+++ b/core/res/res/drawable-xhdpi/perm_group_storage.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_sync_settings.png b/core/res/res/drawable-xhdpi/perm_group_sync_settings.png
index 7249716..252a2a0 100644
--- a/core/res/res/drawable-xhdpi/perm_group_sync_settings.png
+++ b/core/res/res/drawable-xhdpi/perm_group_sync_settings.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_system_clock.png b/core/res/res/drawable-xhdpi/perm_group_system_clock.png
index bf829e4..da8a915 100644
--- a/core/res/res/drawable-xhdpi/perm_group_system_clock.png
+++ b/core/res/res/drawable-xhdpi/perm_group_system_clock.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_system_tools.png b/core/res/res/drawable-xhdpi/perm_group_system_tools.png
index 8a942b6..047c60c 100644
--- a/core/res/res/drawable-xhdpi/perm_group_system_tools.png
+++ b/core/res/res/drawable-xhdpi/perm_group_system_tools.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_user_dictionary.png b/core/res/res/drawable-xhdpi/perm_group_user_dictionary.png
index 345b29f..35d7d5f 100644
--- a/core/res/res/drawable-xhdpi/perm_group_user_dictionary.png
+++ b/core/res/res/drawable-xhdpi/perm_group_user_dictionary.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_user_dictionary_write.png b/core/res/res/drawable-xhdpi/perm_group_user_dictionary_write.png
index f0a98a3..74e25ac 100644
--- a/core/res/res/drawable-xhdpi/perm_group_user_dictionary_write.png
+++ b/core/res/res/drawable-xhdpi/perm_group_user_dictionary_write.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_voicemail.png b/core/res/res/drawable-xhdpi/perm_group_voicemail.png
index 53417ba..430964d 100644
--- a/core/res/res/drawable-xhdpi/perm_group_voicemail.png
+++ b/core/res/res/drawable-xhdpi/perm_group_voicemail.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/perm_group_wallpaper.png b/core/res/res/drawable-xhdpi/perm_group_wallpaper.png
index 6cac9bf..3b698d8 100644
--- a/core/res/res/drawable-xhdpi/perm_group_wallpaper.png
+++ b/core/res/res/drawable-xhdpi/perm_group_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_background_qntm_mult.9.png b/core/res/res/drawable-xhdpi/popup_background_mtrl_mult.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/popup_background_qntm_mult.9.png
rename to core/res/res/drawable-xhdpi/popup_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/progress_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/progress_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/progress_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/progress_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/progress_primary_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/progress_primary_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/progress_primary_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/progress_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrollbar_handle_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/scrollbar_handle_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrollbar_handle_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/scrollbar_handle_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_000.png
rename to core/res/res/drawable-xhdpi/scrubber_control_from_pressed_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_001.png
rename to core/res/res/drawable-xhdpi/scrubber_control_from_pressed_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_002.png
rename to core/res/res/drawable-xhdpi/scrubber_control_from_pressed_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_003.png
rename to core/res/res/drawable-xhdpi/scrubber_control_from_pressed_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_004.png
rename to core/res/res/drawable-xhdpi/scrubber_control_from_pressed_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-xhdpi/scrubber_control_from_pressed_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_from_pressed_qntm_005.png
rename to core/res/res/drawable-xhdpi/scrubber_control_from_pressed_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_off_qntm_alpha.png b/core/res/res/drawable-xhdpi/scrubber_control_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_off_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/scrubber_control_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_off_pressed_qntm_alpha.png b/core/res/res/drawable-xhdpi/scrubber_control_off_pressed_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_off_pressed_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/scrubber_control_off_pressed_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_on_qntm_alpha.png b/core/res/res/drawable-xhdpi/scrubber_control_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_on_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/scrubber_control_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_qntm_alpha.png b/core/res/res/drawable-xhdpi/scrubber_control_on_pressed_mtrl_alpha.png
similarity index 100%
copy from core/res/res/drawable-xhdpi/btn_radio_on_pressed_qntm_alpha.png
copy to core/res/res/drawable-xhdpi/scrubber_control_on_pressed_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_on_pressed_qntm_alpha.png b/core/res/res/drawable-xhdpi/scrubber_control_on_pressed_qntm_alpha.png
deleted file mode 100644
index a7ed0f8..0000000
--- a/core/res/res/drawable-xhdpi/scrubber_control_on_pressed_qntm_alpha.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_000.png
rename to core/res/res/drawable-xhdpi/scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_001.png
rename to core/res/res/drawable-xhdpi/scrubber_control_to_pressed_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_002.png
rename to core/res/res/drawable-xhdpi/scrubber_control_to_pressed_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_003.png
rename to core/res/res/drawable-xhdpi/scrubber_control_to_pressed_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_004.png
rename to core/res/res/drawable-xhdpi/scrubber_control_to_pressed_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-xhdpi/scrubber_control_to_pressed_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_control_to_pressed_qntm_005.png
rename to core/res/res/drawable-xhdpi/scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_primary_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/scrubber_primary_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_primary_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/scrubber_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/scrubber_track_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/scrubber_track_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/scrubber_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_qntm_am_alpha.9.png b/core/res/res/drawable-xhdpi/spinner_mtrl_am_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/spinner_qntm_am_alpha.9.png
rename to core/res/res/drawable-xhdpi/spinner_mtrl_am_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/switch_track_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/tab_indicator_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/tab_indicator_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/tab_indicator_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/tab_indicator_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_cursor_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/text_cursor_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/text_cursor_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/text_cursor_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_select_handle_left_qntm_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/text_select_handle_left_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_select_handle_middle_qntm_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_middle_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/text_select_handle_middle_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/text_select_handle_middle_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_select_handle_right_qntm_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/text_select_handle_right_qntm_alpha.png
rename to core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_activated_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/textfield_activated_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/textfield_activated_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_default_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/textfield_default_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/textfield_default_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_activated_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/textfield_search_activated_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/textfield_search_activated_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_default_qntm_alpha.9.png b/core/res/res/drawable-xhdpi/textfield_search_default_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/textfield_search_default_qntm_alpha.9.png
rename to core/res/res/drawable-xhdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_share_pack_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_share_pack_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ab_share_pack_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/ab_share_pack_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ab_solid_shadow_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/ab_solid_shadow_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ab_solid_shadow_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/ab_solid_shadow_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_cab_done_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_cab_done_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_cab_done_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/btn_cab_done_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_000.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_001.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_002.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_003.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_004.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_005.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_006.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_007.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_008.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_009.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_010.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_011.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_012.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_013.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_014.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_off_qntm_015.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_000.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_001.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_002.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_003.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_004.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_005.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_006.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_007.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_008.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_009.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_010.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_011.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_012.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_013.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_014.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_check_to_on_qntm_015.png
rename to core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_code_lock_default_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_code_lock_default_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_code_lock_default_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_code_lock_default_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_code_lock_touched_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_code_lock_touched_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_code_lock_touched_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_code_lock_touched_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/btn_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00000_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00000_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00000_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00001_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00001_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00001_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00002_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00002_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00002_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00003_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00003_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00003_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00004_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00004_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00004_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00005_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00005_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00005_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00006_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00006_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00006_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00007_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00007_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00007_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00008_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00008_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00008_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00009_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00009_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00009_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00010_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00010_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00010_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00011_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00011_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00011_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00012_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00012_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00012_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00013_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00013_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00013_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00014_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00014_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00014_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00015_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_anim_00015_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_radio_anim_00015_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_000.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_001.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_002.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_003.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_004.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_005.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_006.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_007.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_008.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_009.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_010.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_011.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_012.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_013.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_014.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_off_qntm_015.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_off_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_000.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_001.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_002.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_003.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_004.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_005.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_006.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_007.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_008.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_009.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_010.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_011.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_012.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_013.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_014.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_radio_to_on_qntm_015.png
rename to core/res/res/drawable-xxhdpi/btn_radio_to_on_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_rating_star_off_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_rating_star_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_rating_star_on_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_rating_star_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_star_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_star_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/btn_star_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_000.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_001.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_002.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_003.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_004.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_005.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_006.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_007.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_008.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_009.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_010.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_011.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_012.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_013.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_off_qntm_014.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_000.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_001.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_002.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_003.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_004.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_005.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_006.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_007.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_008.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_009.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_010.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_011.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_012.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_013.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_switch_to_on_qntm_014.png
rename to core/res/res/drawable-xxhdpi/btn_switch_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_toggle_indicator_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/btn_toggle_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/btn_toggle_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_background_mtrl_mult.9.png b/core/res/res/drawable-xxhdpi/dialog_background_mtrl_mult.9.png
new file mode 100644
index 0000000..bb9debb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/expander_close_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/expander_close_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/expander_close_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/expander_close_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/expander_open_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/expander_open_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/expander_open_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/expander_open_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/fastscroll_thumb_qntm_alpha.png b/core/res/res/drawable-xxhdpi/fastscroll_thumb_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/fastscroll_thumb_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/fastscroll_thumb_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/fastscroll_track_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/fastscroll_track_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/fastscroll_track_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/fastscroll_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_ab_back_qntm_am_alpha.png b/core/res/res/drawable-xxhdpi/ic_ab_back_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_ab_back_qntm_am_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_ab_back_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_afw_icon.png b/core/res/res/drawable-xxhdpi/ic_afw_icon.png
new file mode 100644
index 0000000..6888377
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_afw_icon.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_cab_done_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_cab_done_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_cab_done_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_cab_done_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_clear_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_clear_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_clear_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_clear_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_commit_search_api_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_commit_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_commit_search_api_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_commit_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_dialog_alert_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_dialog_alert_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_dialog_alert_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_dialog_alert_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_find_next_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_find_next_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_find_next_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_find_next_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_find_previous_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_find_previous_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_find_previous_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_find_previous_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_go_search_api_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_go_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_go_search_api_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_go_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_media_route_disabled_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_media_route_disabled_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_off_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_media_route_off_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_media_route_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_media_route_on_0_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_media_route_on_0_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_media_route_on_1_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_media_route_on_1_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_media_route_on_2_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_media_route_on_2_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_media_route_on_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_media_route_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_copy_qntm_am_alpha.png b/core/res/res/drawable-xxhdpi/ic_menu_copy_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_menu_copy_qntm_am_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_menu_copy_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_cut_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_menu_cut_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_menu_cut_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_menu_cut_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_find_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_menu_find_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_menu_find_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_menu_find_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_menu_moreoverflow_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_paste_qntm_am_alpha.png b/core/res/res/drawable-xxhdpi/ic_menu_paste_mtrl_am_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_menu_paste_qntm_am_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_menu_paste_mtrl_am_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_search_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_menu_search_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_menu_search_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_menu_search_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_selectall_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_menu_selectall_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_menu_selectall_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_menu_selectall_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_menu_share_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_menu_share_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_menu_share_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_menu_share_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_search_api_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_search_api_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_voice_search_api_qntm_alpha.png b/core/res/res/drawable-xxhdpi/ic_voice_search_api_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/ic_voice_search_api_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/ic_voice_search_api_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/indicator_code_lock_drag_direction_up_qntm_alpha.png b/core/res/res/drawable-xxhdpi/indicator_code_lock_drag_direction_up_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/indicator_code_lock_drag_direction_up_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/indicator_code_lock_drag_direction_up_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_default_qntm_alpha.png b/core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_default_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_default_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_default_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_qntm_alpha.png b/core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/indicator_code_lock_point_area_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_divider_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/list_divider_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/list_divider_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/list_divider_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_section_divider_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/list_section_divider_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/list_section_divider_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/list_section_divider_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_accessibility_features.png b/core/res/res/drawable-xxhdpi/perm_group_accessibility_features.png
index 75cfa8f..5a63b68 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_accessibility_features.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_accessibility_features.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_accounts.png b/core/res/res/drawable-xxhdpi/perm_group_accounts.png
index 148c5d1..2fc3baa 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_accounts.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_accounts.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_affects_battery.png b/core/res/res/drawable-xxhdpi/perm_group_affects_battery.png
index b453a97..63561be 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_affects_battery.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_affects_battery.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_app_info.png b/core/res/res/drawable-xxhdpi/perm_group_app_info.png
index c723e78..fc407f3 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_app_info.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_app_info.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_audio_settings.png b/core/res/res/drawable-xxhdpi/perm_group_audio_settings.png
index 36109e5..23b5d97 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_audio_settings.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_audio_settings.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_bluetooth.png b/core/res/res/drawable-xxhdpi/perm_group_bluetooth.png
index f545010..2dc9b23 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_bluetooth.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_bookmarks.png b/core/res/res/drawable-xxhdpi/perm_group_bookmarks.png
index ddfcfd5..883bad3 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_bookmarks.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_bookmarks.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_calendar.png b/core/res/res/drawable-xxhdpi/perm_group_calendar.png
index 75f7f77..08f0474 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_calendar.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_calendar.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_camera.png b/core/res/res/drawable-xxhdpi/perm_group_camera.png
index 2ee83f6..88a3d0e 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_camera.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_camera.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_device_alarms.png b/core/res/res/drawable-xxhdpi/perm_group_device_alarms.png
index 4218c29..12ab22f 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_device_alarms.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_device_alarms.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_display.png b/core/res/res/drawable-xxhdpi/perm_group_display.png
index a03e670..44e695e 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_display.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_display.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_location.png b/core/res/res/drawable-xxhdpi/perm_group_location.png
index 4ac3fb4..3a83d8b 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_location.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_location.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_messages.png b/core/res/res/drawable-xxhdpi/perm_group_messages.png
index f406a9d..9e2ef73 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_messages.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_messages.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_microphone.png b/core/res/res/drawable-xxhdpi/perm_group_microphone.png
index 6137b86..65a6bf2 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_microphone.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_microphone.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_network.png b/core/res/res/drawable-xxhdpi/perm_group_network.png
index 72d2ef0..4bdb1ba 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_network.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_network.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_personal_info.png b/core/res/res/drawable-xxhdpi/perm_group_personal_info.png
index fe18ec9..c81a2a5 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_personal_info.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_personal_info.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_phone_calls.png b/core/res/res/drawable-xxhdpi/perm_group_phone_calls.png
index acfa435..e4daafb 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_phone_calls.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_phone_calls.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_screenlock.png b/core/res/res/drawable-xxhdpi/perm_group_screenlock.png
index 2fd88ff..3097363 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_screenlock.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_screenlock.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_shortrange_network.png b/core/res/res/drawable-xxhdpi/perm_group_shortrange_network.png
index 72d2ef0..6b21718 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_shortrange_network.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_shortrange_network.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_social_info.png b/core/res/res/drawable-xxhdpi/perm_group_social_info.png
index 73076e0..076fd19 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_social_info.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_social_info.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_status_bar.png b/core/res/res/drawable-xxhdpi/perm_group_status_bar.png
index 380fd66..eda264b 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_status_bar.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_status_bar.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_storage.png b/core/res/res/drawable-xxhdpi/perm_group_storage.png
index b2da3ae..837211e 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_storage.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_storage.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_sync_settings.png b/core/res/res/drawable-xxhdpi/perm_group_sync_settings.png
index 60aecd1..15ab0fc 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_sync_settings.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_sync_settings.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_system_clock.png b/core/res/res/drawable-xxhdpi/perm_group_system_clock.png
index 30cc29c..9149497 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_system_clock.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_system_clock.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_system_tools.png b/core/res/res/drawable-xxhdpi/perm_group_system_tools.png
index 129c221..0332e40 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_system_tools.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_system_tools.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_user_dictionary.png b/core/res/res/drawable-xxhdpi/perm_group_user_dictionary.png
index 020167f..5b6ea3b 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_user_dictionary.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_user_dictionary.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_user_dictionary_write.png b/core/res/res/drawable-xxhdpi/perm_group_user_dictionary_write.png
index 6218f62..d92e719 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_user_dictionary_write.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_user_dictionary_write.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_voicemail.png b/core/res/res/drawable-xxhdpi/perm_group_voicemail.png
index 336cb6b..8f08516 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_voicemail.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_voicemail.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/perm_group_wallpaper.png b/core/res/res/drawable-xxhdpi/perm_group_wallpaper.png
index e7d8f43..9c87e9a 100644
--- a/core/res/res/drawable-xxhdpi/perm_group_wallpaper.png
+++ b/core/res/res/drawable-xxhdpi/perm_group_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/popup_background_qntm_mult.9.png b/core/res/res/drawable-xxhdpi/popup_background_mtrl_mult.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/popup_background_qntm_mult.9.png
rename to core/res/res/drawable-xxhdpi/popup_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progress_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/progress_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/progress_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/progress_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progress_primary_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/progress_primary_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/progress_primary_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/progress_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrollbar_handle_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/scrollbar_handle_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrollbar_handle_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/scrollbar_handle_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_000.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_001.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_002.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_003.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_004.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_qntm_005.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_from_pressed_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_off_qntm_alpha.png b/core/res/res/drawable-xxhdpi/scrubber_control_off_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_off_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_off_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_off_pressed_qntm_alpha.png b/core/res/res/drawable-xxhdpi/scrubber_control_off_pressed_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_off_pressed_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_off_pressed_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_on_qntm_alpha.png b/core/res/res/drawable-xxhdpi/scrubber_control_on_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_on_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_on_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_on_pressed_qntm_alpha.png b/core/res/res/drawable-xxhdpi/scrubber_control_on_pressed_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_on_pressed_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_on_pressed_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_000.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_001.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_002.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_003.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_004.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_qntm_005.png
rename to core/res/res/drawable-xxhdpi/scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_primary_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/scrubber_primary_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_primary_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/scrubber_primary_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/scrubber_track_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/scrubber_track_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/scrubber_track_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/scrubber_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_qntm_am_alpha.9.png b/core/res/res/drawable-xxhdpi/spinner_mtrl_am_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/spinner_qntm_am_alpha.9.png
rename to core/res/res/drawable-xxhdpi/spinner_mtrl_am_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/switch_track_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/tab_indicator_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/tab_indicator_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/tab_indicator_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/tab_indicator_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_cursor_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/text_cursor_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/text_cursor_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/text_cursor_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_left_qntm_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/text_select_handle_left_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_middle_qntm_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_middle_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/text_select_handle_middle_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/text_select_handle_middle_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_right_qntm_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/text_select_handle_right_qntm_alpha.png
rename to core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_activated_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/textfield_activated_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/textfield_activated_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_default_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/textfield_default_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/textfield_default_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_activated_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/textfield_search_activated_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/textfield_search_activated_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_default_qntm_alpha.9.png b/core/res/res/drawable-xxhdpi/textfield_search_default_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/textfield_search_default_qntm_alpha.9.png
rename to core/res/res/drawable-xxhdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_000.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_001.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_002.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_003.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_004.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_005.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_006.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_007.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_008.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_009.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_010.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_011.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_012.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_013.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_014.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_015.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_off_qntm_015.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_000.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_001.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_002.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_003.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_004.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_005.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_006.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_007.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_008.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_009.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_010.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_011.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_012.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_013.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_014.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_015.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_check_to_on_qntm_015.png
rename to core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_qntm_alpha.9.png b/core/res/res/drawable-xxxhdpi/btn_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_qntm_alpha.9.png
rename to core/res/res/drawable-xxxhdpi/btn_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_000.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_001.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_002.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_003.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_004.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_005.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_006.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_007.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_008.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_009.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_010.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_011.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_012.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_013.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_014.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_015.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_off_qntm_015.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_off_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_000.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_001.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_002.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_003.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_004.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_005.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_006.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_007.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_008.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_009.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_010.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_011.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_012.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_013.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_014.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_015.png b/core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_015.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_radio_to_on_qntm_015.png
rename to core/res/res/drawable-xxxhdpi/btn_radio_to_on_mtrl_015.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_000.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_001.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_002.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_003.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_004.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_005.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_006.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_007.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_008.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_009.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_010.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_011.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_012.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_013.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_off_qntm_014.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_off_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_000.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_000.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_001.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_001.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_002.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_002.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_003.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_003.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_004.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_004.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_005.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_005.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_006.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_006.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_006.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_006.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_007.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_007.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_007.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_007.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_008.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_008.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_008.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_008.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_009.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_009.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_009.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_009.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_010.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_010.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_010.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_010.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_011.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_011.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_011.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_011.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_012.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_012.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_012.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_012.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_013.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_013.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_013.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_013.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_014.png b/core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_014.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_switch_to_on_qntm_014.png
rename to core/res/res/drawable-xxxhdpi/btn_switch_to_on_mtrl_014.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_qntm_alpha.9.png b/core/res/res/drawable-xxxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_toggle_indicator_qntm_alpha.9.png
rename to core/res/res/drawable-xxxhdpi/btn_toggle_indicator_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_toggle_qntm_alpha.9.png b/core/res/res/drawable-xxxhdpi/btn_toggle_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/btn_toggle_qntm_alpha.9.png
rename to core/res/res/drawable-xxxhdpi/btn_toggle_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/indicator_code_lock_drag_direction_up_qntm_alpha.png b/core/res/res/drawable-xxxhdpi/indicator_code_lock_drag_direction_up_mtrl_alpha.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/indicator_code_lock_drag_direction_up_qntm_alpha.png
rename to core/res/res/drawable-xxxhdpi/indicator_code_lock_drag_direction_up_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_accessibility_features.png b/core/res/res/drawable-xxxhdpi/perm_group_accessibility_features.png
new file mode 100644
index 0000000..8cebecf
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_accessibility_features.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_accounts.png b/core/res/res/drawable-xxxhdpi/perm_group_accounts.png
new file mode 100644
index 0000000..1d9db83
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_accounts.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_affects_battery.png b/core/res/res/drawable-xxxhdpi/perm_group_affects_battery.png
new file mode 100644
index 0000000..3b6300a
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_affects_battery.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_app_info.png b/core/res/res/drawable-xxxhdpi/perm_group_app_info.png
new file mode 100644
index 0000000..b54b98a
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_app_info.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_audio_settings.png b/core/res/res/drawable-xxxhdpi/perm_group_audio_settings.png
new file mode 100644
index 0000000..ec88cdd
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_audio_settings.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_bluetooth.png b/core/res/res/drawable-xxxhdpi/perm_group_bluetooth.png
new file mode 100644
index 0000000..6f6409d
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_bookmarks.png b/core/res/res/drawable-xxxhdpi/perm_group_bookmarks.png
new file mode 100644
index 0000000..f8f3f44
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_bookmarks.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_calendar.png b/core/res/res/drawable-xxxhdpi/perm_group_calendar.png
new file mode 100644
index 0000000..d6243b1
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_calendar.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_camera.png b/core/res/res/drawable-xxxhdpi/perm_group_camera.png
new file mode 100644
index 0000000..fdc4b44
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_camera.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_device_alarms.png b/core/res/res/drawable-xxxhdpi/perm_group_device_alarms.png
new file mode 100644
index 0000000..00707d4
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_device_alarms.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_display.png b/core/res/res/drawable-xxxhdpi/perm_group_display.png
new file mode 100644
index 0000000..ca4f44b
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_display.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_location.png b/core/res/res/drawable-xxxhdpi/perm_group_location.png
new file mode 100644
index 0000000..a1019b2
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_location.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_messages.png b/core/res/res/drawable-xxxhdpi/perm_group_messages.png
new file mode 100644
index 0000000..f7165fe
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_messages.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_microphone.png b/core/res/res/drawable-xxxhdpi/perm_group_microphone.png
new file mode 100644
index 0000000..a85e4cd
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_microphone.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_network.png b/core/res/res/drawable-xxxhdpi/perm_group_network.png
new file mode 100644
index 0000000..07f1eb7
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_network.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_personal_info.png b/core/res/res/drawable-xxxhdpi/perm_group_personal_info.png
new file mode 100644
index 0000000..11eb453
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_personal_info.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_phone_calls.png b/core/res/res/drawable-xxxhdpi/perm_group_phone_calls.png
new file mode 100644
index 0000000..f4e6b9f
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_phone_calls.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_screenlock.png b/core/res/res/drawable-xxxhdpi/perm_group_screenlock.png
new file mode 100644
index 0000000..d559dce
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_screenlock.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_shortrange_network.png b/core/res/res/drawable-xxxhdpi/perm_group_shortrange_network.png
new file mode 100644
index 0000000..3998ab6
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_shortrange_network.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_social_info.png b/core/res/res/drawable-xxxhdpi/perm_group_social_info.png
new file mode 100644
index 0000000..3b17e39
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_social_info.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_status_bar.png b/core/res/res/drawable-xxxhdpi/perm_group_status_bar.png
new file mode 100644
index 0000000..1b02702
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_status_bar.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_storage.png b/core/res/res/drawable-xxxhdpi/perm_group_storage.png
new file mode 100644
index 0000000..918b3ed
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_storage.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_sync_settings.png b/core/res/res/drawable-xxxhdpi/perm_group_sync_settings.png
new file mode 100644
index 0000000..12f90c5
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_sync_settings.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_system_clock.png b/core/res/res/drawable-xxxhdpi/perm_group_system_clock.png
new file mode 100644
index 0000000..afd968b
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_system_clock.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_system_tools.png b/core/res/res/drawable-xxxhdpi/perm_group_system_tools.png
new file mode 100644
index 0000000..dfcb702
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_system_tools.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_user_dictionary.png b/core/res/res/drawable-xxxhdpi/perm_group_user_dictionary.png
new file mode 100644
index 0000000..32942ca
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_user_dictionary.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_user_dictionary_write.png b/core/res/res/drawable-xxxhdpi/perm_group_user_dictionary_write.png
new file mode 100644
index 0000000..343551f
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_user_dictionary_write.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_voicemail.png b/core/res/res/drawable-xxxhdpi/perm_group_voicemail.png
new file mode 100644
index 0000000..7aeb786
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_voicemail.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/perm_group_wallpaper.png b/core/res/res/drawable-xxxhdpi/perm_group_wallpaper.png
new file mode 100644
index 0000000..3c08471
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/perm_group_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_000.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_000.png
rename to core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_001.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_001.png
rename to core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_002.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_002.png
rename to core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_003.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_003.png
rename to core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_004.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_004.png
rename to core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_005.png b/core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_qntm_005.png
rename to core/res/res/drawable-xxxhdpi/scrubber_control_from_pressed_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_000.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_mtrl_000.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_000.png
rename to core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_mtrl_000.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_001.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_mtrl_001.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_001.png
rename to core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_mtrl_001.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_002.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_mtrl_002.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_002.png
rename to core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_mtrl_002.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_003.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_mtrl_003.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_003.png
rename to core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_mtrl_003.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_004.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_mtrl_004.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_004.png
rename to core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_mtrl_004.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_005.png b/core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_mtrl_005.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_qntm_005.png
rename to core/res/res/drawable-xxxhdpi/scrubber_control_to_pressed_mtrl_005.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/switch_track_qntm_alpha.9.png b/core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/switch_track_qntm_alpha.9.png
rename to core/res/res/drawable-xxxhdpi/switch_track_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/tab_indicator_qntm_alpha.9.png b/core/res/res/drawable-xxxhdpi/tab_indicator_mtrl_alpha.9.png
similarity index 100%
rename from core/res/res/drawable-xxxhdpi/tab_indicator_qntm_alpha.9.png
rename to core/res/res/drawable-xxxhdpi/tab_indicator_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ab_share_pack_material.xml
similarity index 93%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ab_share_pack_material.xml
index fee196c..1f0478e 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ab_share_pack_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ab_share_pack_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ab_share_pack_quantum.xml b/core/res/res/drawable/ab_share_pack_quantum.xml
deleted file mode 100644
index 7d33ff4d..0000000
--- a/core/res/res/drawable/ab_share_pack_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ab_share_pack_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ab_solid_shadow_quantum.xml b/core/res/res/drawable/ab_solid_shadow_material.xml
similarity index 93%
rename from core/res/res/drawable/ab_solid_shadow_quantum.xml
rename to core/res/res/drawable/ab_solid_shadow_material.xml
index 88e142a..eee52c8 100644
--- a/core/res/res/drawable/ab_solid_shadow_quantum.xml
+++ b/core/res/res/drawable/ab_solid_shadow_material.xml
@@ -15,5 +15,5 @@
-->
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ab_solid_shadow_qntm_alpha"
+ android:src="@drawable/ab_solid_shadow_mtrl_alpha"
android:tint="@color/black" />
diff --git a/core/res/res/drawable/activated_background_quantum.xml b/core/res/res/drawable/activated_background_material.xml
similarity index 100%
rename from core/res/res/drawable/activated_background_quantum.xml
rename to core/res/res/drawable/activated_background_material.xml
diff --git a/core/res/res/drawable/btn_borderless_quantum.xml b/core/res/res/drawable/btn_borderless_material.xml
similarity index 87%
rename from core/res/res/drawable/btn_borderless_quantum.xml
rename to core/res/res/drawable/btn_borderless_material.xml
index 2cd7ed6..a459089 100644
--- a/core/res/res/drawable/btn_borderless_quantum.xml
+++ b/core/res/res/drawable/btn_borderless_material.xml
@@ -15,7 +15,7 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:tint="?attr/colorControlHighlight">
+ android:color="?attr/colorControlHighlight">
<item android:id="@id/mask"
- android:drawable="@drawable/btn_qntm_alpha" />
+ android:drawable="@drawable/btn_mtrl_alpha" />
</ripple>
diff --git a/core/res/res/drawable/btn_cab_done_quantum.xml b/core/res/res/drawable/btn_cab_done_material.xml
similarity index 89%
rename from core/res/res/drawable/btn_cab_done_quantum.xml
rename to core/res/res/drawable/btn_cab_done_material.xml
index 51e06bb..36cc196 100644
--- a/core/res/res/drawable/btn_cab_done_quantum.xml
+++ b/core/res/res/drawable/btn_cab_done_material.xml
@@ -21,11 +21,11 @@
<color android:color="?attr/colorControlHighlight" />
</item>
<item android:state_focused="true" android:state_enabled="true">
- <nine-patch android:src="@drawable/btn_cab_done_qntm_alpha"
+ <nine-patch android:src="@drawable/btn_cab_done_mtrl_alpha"
android:tint="?attr/colorControlHighlight" />
</item>
<item android:state_enabled="true">
- <nine-patch android:src="@drawable/btn_cab_done_qntm_alpha"
+ <nine-patch android:src="@drawable/btn_cab_done_mtrl_alpha"
android:tint="?attr/colorButtonNormal" />
</item>
</selector>
diff --git a/core/res/res/drawable/btn_check_material_anim.xml b/core/res/res/drawable/btn_check_material_anim.xml
new file mode 100644
index 0000000..73b8a3e
--- /dev/null
+++ b/core/res/res/drawable/btn_check_material_anim.xml
@@ -0,0 +1,135 @@
+<?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.
+-->
+
+<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/colorControlActivated" 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/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_001" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_002" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_003" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_004" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_005" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_006" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_check_to_on_mtrl_007" android:tint="?attr/colorControlActivated" />
+ </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/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_009" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_010" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_011" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_012" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_013" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_014" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_check_to_off_mtrl_015" android:tint="?attr/colorControlActivated" />
+ </item>
+ </animation-list>
+ </transition>
+</animated-selector>
+
diff --git a/core/res/res/drawable/btn_check_quantum_anim.xml b/core/res/res/drawable/btn_check_quantum_anim.xml
deleted file mode 100644
index b16875e..0000000
--- a/core/res/res/drawable/btn_check_quantum_anim.xml
+++ /dev/null
@@ -1,135 +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.
--->
-
-<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_qntm_015" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
- </item>
- <item android:state_enabled="false">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_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_qntm_015" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:id="@+id/off">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_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_qntm_000" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_001" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_002" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_003" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_004" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_005" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_006" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_007" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_008" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_009" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_010" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_011" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_012" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_013" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_014" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_on_qntm_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_qntm_000" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_001" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_002" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_003" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_004" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_005" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_006" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_007" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_008" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_009" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_010" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_011" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_012" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_013" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_014" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_check_to_off_qntm_015" android:tint="?attr/colorControlActivated" />
- </item>
- </animation-list>
- </transition>
-</animated-selector>
-
diff --git a/core/res/res/drawable/btn_default_quantum.xml b/core/res/res/drawable/btn_default_material.xml
similarity index 88%
rename from core/res/res/drawable/btn_default_quantum.xml
rename to core/res/res/drawable/btn_default_material.xml
index 61193fe..9cee3ab 100644
--- a/core/res/res/drawable/btn_default_quantum.xml
+++ b/core/res/res/drawable/btn_default_material.xml
@@ -15,9 +15,9 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:tint="?attr/colorControlHighlight">
+ android:color="?attr/colorControlHighlight">
<item>
- <nine-patch android:src="@drawable/btn_qntm_alpha"
+ <nine-patch android:src="@drawable/btn_mtrl_alpha"
android:tint="?attr/colorButtonNormal" />
</item>
</ripple>
diff --git a/core/res/res/drawable/btn_radio_material_anim.xml b/core/res/res/drawable/btn_radio_material_anim.xml
new file mode 100644
index 0000000..0be590e
--- /dev/null
+++ b/core/res/res/drawable/btn_radio_material_anim.xml
@@ -0,0 +1,134 @@
+<?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.
+-->
+
+<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_radio_to_on_mtrl_015" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
+ </item>
+ <item android:state_enabled="false">
+ <bitmap android:src="@drawable/btn_radio_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_radio_to_on_mtrl_015" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:id="@+id/off">
+ <bitmap android:src="@drawable/btn_radio_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_radio_to_on_mtrl_000" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_001" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_002" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_003" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_004" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_005" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_006" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_007" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_008" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_009" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_010" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_011" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_012" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_013" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_on_mtrl_014" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_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_radio_to_off_mtrl_000" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_001" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_002" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_003" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_004" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_005" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_006" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_007" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_008" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_009" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_010" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_011" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_012" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_013" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_014" android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:duration="15">
+ <bitmap android:src="@drawable/btn_radio_to_off_mtrl_015" android:tint="?attr/colorControlActivated" />
+ </item>
+ </animation-list>
+ </transition>
+</animated-selector>
diff --git a/core/res/res/drawable/btn_radio_quantum_anim.xml b/core/res/res/drawable/btn_radio_quantum_anim.xml
deleted file mode 100644
index cd9b518..0000000
--- a/core/res/res/drawable/btn_radio_quantum_anim.xml
+++ /dev/null
@@ -1,134 +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.
--->
-
-<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_radio_to_on_qntm_015" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
- </item>
- <item android:state_enabled="false">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_000" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" />
- </item>
- <item android:state_checked="true" android:id="@+id/on">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_015" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:id="@+id/off">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_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_radio_to_on_qntm_000" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_001" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_002" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_003" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_004" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_005" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_006" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_007" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_008" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_009" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_010" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_011" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_012" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_013" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_014" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_on_qntm_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_radio_to_off_qntm_000" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_001" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_002" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_003" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_004" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_005" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_006" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_007" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_008" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_009" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_010" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_011" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_012" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_013" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_014" android:tint="?attr/colorControlActivated" />
- </item>
- <item android:duration="15">
- <bitmap android:src="@drawable/btn_radio_to_off_qntm_015" android:tint="?attr/colorControlActivated" />
- </item>
- </animation-list>
- </transition>
-</animated-selector>
diff --git a/core/res/res/drawable/btn_star_quantum.xml b/core/res/res/drawable/btn_star_material.xml
similarity index 85%
rename from core/res/res/drawable/btn_star_quantum.xml
rename to core/res/res/drawable/btn_star_material.xml
index 512cd57..29862d2 100644
--- a/core/res/res/drawable/btn_star_quantum.xml
+++ b/core/res/res/drawable/btn_star_material.xml
@@ -16,15 +16,15 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
- <bitmap android:src="@drawable/btn_star_qntm_alpha"
+ <bitmap android:src="@drawable/btn_star_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item android:state_pressed="true">
- <bitmap android:src="@drawable/btn_star_qntm_alpha"
+ <bitmap android:src="@drawable/btn_star_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item>
- <bitmap android:src="@drawable/btn_star_qntm_alpha"
+ <bitmap android:src="@drawable/btn_star_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
</selector>
diff --git a/core/res/res/drawable/btn_toggle_quantum.xml b/core/res/res/drawable/btn_toggle_material.xml
similarity index 92%
rename from core/res/res/drawable/btn_toggle_quantum.xml
rename to core/res/res/drawable/btn_toggle_material.xml
index e235598..73fe4d3 100644
--- a/core/res/res/drawable/btn_toggle_quantum.xml
+++ b/core/res/res/drawable/btn_toggle_material.xml
@@ -21,9 +21,9 @@
android:insetRight="4dp">
<layer-list android:paddingMode="stack">
<item>
- <ripple android:tint="?attr/colorControlHighlight">
+ <ripple android:color="?attr/colorControlHighlight">
<item>
- <nine-patch android:src="@drawable/btn_toggle_qntm_alpha"
+ <nine-patch android:src="@drawable/btn_toggle_mtrl_alpha"
android:tint="?attr/colorButtonNormal" />
</item>
</ripple>
@@ -31,11 +31,11 @@
<item>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false">
- <nine-patch android:src="@drawable/btn_toggle_indicator_qntm_alpha"
+ <nine-patch android:src="@drawable/btn_toggle_indicator_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item android:state_checked="true">
- <nine-patch android:src="@drawable/btn_toggle_indicator_qntm_alpha"
+ <nine-patch android:src="@drawable/btn_toggle_indicator_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
</item>
</selector>
diff --git a/core/res/res/drawable/dialog_background_quantum.xml b/core/res/res/drawable/dialog_background_material.xml
similarity index 100%
rename from core/res/res/drawable/dialog_background_quantum.xml
rename to core/res/res/drawable/dialog_background_material.xml
diff --git a/core/res/res/drawable/popup_background_quantum.xml b/core/res/res/drawable/dialog_background_shadow_material.xml
similarity index 93%
rename from core/res/res/drawable/popup_background_quantum.xml
rename to core/res/res/drawable/dialog_background_shadow_material.xml
index a4d0291..0554920 100644
--- a/core/res/res/drawable/popup_background_quantum.xml
+++ b/core/res/res/drawable/dialog_background_shadow_material.xml
@@ -15,6 +15,6 @@
-->
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/popup_background_qntm_mult"
+ android:src="@drawable/dialog_background_mtrl_mult"
android:tint="?attr/colorBackground"
android:tintMode="multiply" />
diff --git a/core/res/res/drawable/edit_text_quantum.xml b/core/res/res/drawable/edit_text_material.xml
similarity index 89%
rename from core/res/res/drawable/edit_text_quantum.xml
rename to core/res/res/drawable/edit_text_material.xml
index ab2580a..86cec8f 100644
--- a/core/res/res/drawable/edit_text_quantum.xml
+++ b/core/res/res/drawable/edit_text_material.xml
@@ -15,20 +15,19 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:tint="?attr/colorControlActivated"
- android:tintMode="src_over">
+ android:color="?attr/colorControlActivated">
<item>
<selector>
<item android:state_enabled="false">
- <nine-patch android:src="@drawable/textfield_default_qntm_alpha"
+ <nine-patch android:src="@drawable/textfield_default_mtrl_alpha"
android:tint="?attr/colorControlNormal"
android:alpha="?attr/disabledAlpha" />
</item>
<item>
- <nine-patch android:src="@drawable/textfield_default_qntm_alpha"
+ <nine-patch android:src="@drawable/textfield_default_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
</selector>
</item>
- <item android:id="@+id/mask" android:drawable="@drawable/textfield_activated_qntm_alpha" />
+ <item android:id="@+id/mask" android:drawable="@drawable/textfield_activated_mtrl_alpha" />
</ripple>
diff --git a/core/res/res/drawable/expander_group_quantum.xml b/core/res/res/drawable/expander_group_material.xml
similarity index 87%
rename from core/res/res/drawable/expander_group_quantum.xml
rename to core/res/res/drawable/expander_group_material.xml
index 48245ea..aa41796 100644
--- a/core/res/res/drawable/expander_group_quantum.xml
+++ b/core/res/res/drawable/expander_group_material.xml
@@ -16,11 +16,11 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_expanded="true">
- <nine-patch android:src="@drawable/expander_close_qntm_alpha"
+ <nine-patch android:src="@drawable/expander_close_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item>
- <nine-patch android:src="@drawable/expander_open_qntm_alpha"
+ <nine-patch android:src="@drawable/expander_open_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
</selector>
diff --git a/core/res/res/drawable/fastscroll_thumb_quantum.xml b/core/res/res/drawable/fastscroll_thumb_material.xml
similarity index 87%
rename from core/res/res/drawable/fastscroll_thumb_quantum.xml
rename to core/res/res/drawable/fastscroll_thumb_material.xml
index 496b2ae..1288f0d 100644
--- a/core/res/res/drawable/fastscroll_thumb_quantum.xml
+++ b/core/res/res/drawable/fastscroll_thumb_material.xml
@@ -16,11 +16,11 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
- <bitmap android:src="@drawable/fastscroll_thumb_qntm_alpha"
+ <bitmap android:src="@drawable/fastscroll_thumb_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item>
- <bitmap android:src="@drawable/fastscroll_thumb_qntm_alpha"
+ <bitmap android:src="@drawable/fastscroll_thumb_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
</selector>
diff --git a/core/res/res/drawable/list_divider_quantum.xml b/core/res/res/drawable/fastscroll_track_material.xml
similarity index 92%
copy from core/res/res/drawable/list_divider_quantum.xml
copy to core/res/res/drawable/fastscroll_track_material.xml
index e3d4ba2..60f79b1 100644
--- a/core/res/res/drawable/list_divider_quantum.xml
+++ b/core/res/res/drawable/fastscroll_track_material.xml
@@ -15,5 +15,5 @@
-->
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/list_divider_qntm_alpha"
+ android:src="@drawable/fastscroll_track_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/fastscroll_track_quantum.xml b/core/res/res/drawable/fastscroll_track_quantum.xml
deleted file mode 100644
index 59c35db..0000000
--- a/core/res/res/drawable/fastscroll_track_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/fastscroll_track_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_ab_back_quantum.xml b/core/res/res/drawable/ic_ab_back_material.xml
similarity index 93%
rename from core/res/res/drawable/ic_ab_back_quantum.xml
rename to core/res/res/drawable/ic_ab_back_material.xml
index 65c7584..37455d4 100644
--- a/core/res/res/drawable/ic_ab_back_quantum.xml
+++ b/core/res/res/drawable/ic_ab_back_material.xml
@@ -15,6 +15,6 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_ab_back_qntm_am_alpha"
+ android:src="@drawable/ic_ab_back_mtrl_am_alpha"
android:autoMirrored="true"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_cab_done_material.xml
similarity index 93%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ic_cab_done_material.xml
index fee196c..a370288 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_cab_done_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_cab_done_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_cab_done_quantum.xml b/core/res/res/drawable/ic_cab_done_quantum.xml
deleted file mode 100644
index 97495a8..0000000
--- a/core/res/res/drawable/ic_cab_done_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_cab_done_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_clear_material.xml
similarity index 93%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ic_clear_material.xml
index fee196c..076c0a2 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_clear_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_clear_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_clear_quantum.xml b/core/res/res/drawable/ic_clear_quantum.xml
deleted file mode 100644
index 02f0929..0000000
--- a/core/res/res/drawable/ic_clear_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_clear_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_commit_search_api_material.xml
similarity index 92%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ic_commit_search_api_material.xml
index fee196c..59bd0fa 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_commit_search_api_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_commit_search_api_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_commit_search_api_quantum.xml b/core/res/res/drawable/ic_commit_search_api_quantum.xml
deleted file mode 100644
index 02d08b9..0000000
--- a/core/res/res/drawable/ic_commit_search_api_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_commit_search_api_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_dialog_alert_material.xml
similarity index 93%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ic_dialog_alert_material.xml
index fee196c..41e1ab1 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_dialog_alert_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_dialog_alert_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_dialog_alert_quantum.xml b/core/res/res/drawable/ic_dialog_alert_quantum.xml
deleted file mode 100644
index 05f3630..0000000
--- a/core/res/res/drawable/ic_dialog_alert_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_dialog_alert_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_find_next_material.xml
similarity index 93%
rename from core/res/res/drawable/ic_find_next_quantum.xml
rename to core/res/res/drawable/ic_find_next_material.xml
index fee196c..c6674eb 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_find_next_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_find_next_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_find_previous_material.xml
similarity index 92%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ic_find_previous_material.xml
index fee196c..32fcb31 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_find_previous_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_find_previous_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_find_previous_quantum.xml b/core/res/res/drawable/ic_find_previous_quantum.xml
deleted file mode 100644
index 28f887a..0000000
--- a/core/res/res/drawable/ic_find_previous_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_previous_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_go_search_api_material.xml
similarity index 92%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ic_go_search_api_material.xml
index fee196c..03f6cd5 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_go_search_api_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_go_search_api_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_go_search_api_quantum.xml b/core/res/res/drawable/ic_go_search_api_quantum.xml
deleted file mode 100644
index b5b5cfb..0000000
--- a/core/res/res/drawable/ic_go_search_api_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_go_search_api_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_media_route_connecting_quantum.xml b/core/res/res/drawable/ic_media_route_connecting_material.xml
similarity index 82%
rename from core/res/res/drawable/ic_media_route_connecting_quantum.xml
rename to core/res/res/drawable/ic_media_route_connecting_material.xml
index 0029dd4..51decd3 100644
--- a/core/res/res/drawable/ic_media_route_connecting_quantum.xml
+++ b/core/res/res/drawable/ic_media_route_connecting_material.xml
@@ -18,19 +18,19 @@
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:duration="500">
- <bitmap android:src="@drawable/ic_media_route_on_0_qntm_alpha"
+ <bitmap android:src="@drawable/ic_media_route_on_0_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="500">
- <bitmap android:src="@drawable/ic_media_route_on_1_qntm_alpha"
+ <bitmap android:src="@drawable/ic_media_route_on_1_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="500">
- <bitmap android:src="@drawable/ic_media_route_on_2_qntm_alpha"
+ <bitmap android:src="@drawable/ic_media_route_on_2_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item android:duration="500">
- <bitmap android:src="@drawable/ic_media_route_on_1_qntm_alpha"
+ <bitmap android:src="@drawable/ic_media_route_on_1_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
</animation-list>
diff --git a/core/res/res/drawable/ic_media_route_quantum.xml b/core/res/res/drawable/ic_media_route_material.xml
similarity index 95%
rename from core/res/res/drawable/ic_media_route_quantum.xml
rename to core/res/res/drawable/ic_media_route_material.xml
index 16b63d4..3e3f388 100644
--- a/core/res/res/drawable/ic_media_route_quantum.xml
+++ b/core/res/res/drawable/ic_media_route_material.xml
@@ -17,17 +17,17 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:state_enabled="true"
- android:drawable="@android:drawable/ic_media_route_connecting_quantum" />
+ android:drawable="@android:drawable/ic_media_route_connecting_material" />
<item android:state_activated="true" android:state_enabled="true">
- <bitmap android:src="@android:drawable/ic_media_route_on_qntm_alpha"
+ <bitmap android:src="@android:drawable/ic_media_route_on_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item android:state_enabled="true">
- <bitmap android:src="@android:drawable/ic_media_route_off_qntm_alpha"
+ <bitmap android:src="@android:drawable/ic_media_route_off_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item>
- <bitmap android:src="@android:drawable/ic_media_route_disabled_qntm_alpha"
+ <bitmap android:src="@android:drawable/ic_media_route_disabled_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
</selector>
diff --git a/core/res/res/drawable/ic_menu_copy_quantum.xml b/core/res/res/drawable/ic_menu_copy_material.xml
similarity index 93%
copy from core/res/res/drawable/ic_menu_copy_quantum.xml
copy to core/res/res/drawable/ic_menu_copy_material.xml
index 5f6ce51..877b5ff 100644
--- a/core/res/res/drawable/ic_menu_copy_quantum.xml
+++ b/core/res/res/drawable/ic_menu_copy_material.xml
@@ -15,6 +15,6 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_menu_copy_qntm_am_alpha"
+ android:src="@drawable/ic_menu_copy_mtrl_am_alpha"
android:tint="?attr/colorControlNormal"
android:autoMirrored="true" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_menu_cut_material.xml
similarity index 93%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ic_menu_cut_material.xml
index fee196c..ff8d6e6 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_menu_cut_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_menu_cut_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_menu_cut_quantum.xml b/core/res/res/drawable/ic_menu_cut_quantum.xml
deleted file mode 100644
index 1e4996e..0000000
--- a/core/res/res/drawable/ic_menu_cut_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_menu_cut_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_menu_find_material.xml
similarity index 93%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ic_menu_find_material.xml
index fee196c..00b294e 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_menu_find_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_menu_find_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_menu_find_quantum.xml b/core/res/res/drawable/ic_menu_find_quantum.xml
deleted file mode 100644
index a69c673..0000000
--- a/core/res/res/drawable/ic_menu_find_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_menu_find_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_menu_moreoverflow_material.xml
similarity index 92%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ic_menu_moreoverflow_material.xml
index fee196c..16d4f0c 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_menu_moreoverflow_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_menu_moreoverflow_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_quantum.xml b/core/res/res/drawable/ic_menu_moreoverflow_quantum.xml
deleted file mode 100644
index 7d3fcac..0000000
--- a/core/res/res/drawable/ic_menu_moreoverflow_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_menu_moreoverflow_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_menu_copy_quantum.xml b/core/res/res/drawable/ic_menu_paste_material.xml
similarity index 93%
rename from core/res/res/drawable/ic_menu_copy_quantum.xml
rename to core/res/res/drawable/ic_menu_paste_material.xml
index 5f6ce51..f7bbbf9 100644
--- a/core/res/res/drawable/ic_menu_copy_quantum.xml
+++ b/core/res/res/drawable/ic_menu_paste_material.xml
@@ -15,6 +15,6 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_menu_copy_qntm_am_alpha"
+ android:src="@drawable/ic_menu_paste_mtrl_am_alpha"
android:tint="?attr/colorControlNormal"
android:autoMirrored="true" />
diff --git a/core/res/res/drawable/ic_menu_paste_quantum.xml b/core/res/res/drawable/ic_menu_paste_quantum.xml
deleted file mode 100644
index f590904..0000000
--- a/core/res/res/drawable/ic_menu_paste_quantum.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_menu_paste_qntm_am_alpha"
- android:tint="?attr/colorControlNormal"
- android:autoMirrored="true" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_menu_search_material.xml
similarity index 93%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ic_menu_search_material.xml
index fee196c..78dd62f 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_menu_search_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_menu_search_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_menu_search_quantum.xml b/core/res/res/drawable/ic_menu_search_quantum.xml
deleted file mode 100644
index 2ca8c20..0000000
--- a/core/res/res/drawable/ic_menu_search_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_menu_search_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_menu_selectall_material.xml
similarity index 92%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ic_menu_selectall_material.xml
index fee196c..a431dd5 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_menu_selectall_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_menu_selectall_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_menu_selectall_quantum.xml b/core/res/res/drawable/ic_menu_selectall_quantum.xml
deleted file mode 100644
index fd72ebf..0000000
--- a/core/res/res/drawable/ic_menu_selectall_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_menu_selectall_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_menu_share_material.xml
similarity index 93%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ic_menu_share_material.xml
index fee196c..d9153af 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_menu_share_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_menu_share_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_menu_share_quantum.xml b/core/res/res/drawable/ic_menu_share_quantum.xml
deleted file mode 100644
index f44e06c..0000000
--- a/core/res/res/drawable/ic_menu_share_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_menu_share_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_search_api_material.xml
similarity index 93%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ic_search_api_material.xml
index fee196c..bc18398 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_search_api_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_search_api_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_search_api_quantum.xml b/core/res/res/drawable/ic_search_api_quantum.xml
deleted file mode 100644
index 2bbc294..0000000
--- a/core/res/res/drawable/ic_search_api_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_search_api_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/core/res/res/drawable/ic_voice_search_api_material.xml
similarity index 92%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to core/res/res/drawable/ic_voice_search_api_material.xml
index fee196c..05488fb 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/core/res/res/drawable/ic_voice_search_api_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
+ android:src="@drawable/ic_voice_search_api_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/ic_voice_search_api_quantum.xml b/core/res/res/drawable/ic_voice_search_api_quantum.xml
deleted file mode 100644
index ddb14ef..0000000
--- a/core/res/res/drawable/ic_voice_search_api_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_voice_search_api_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/item_background_borderless_quantum.xml b/core/res/res/drawable/item_background_borderless_material.xml
similarity index 90%
rename from core/res/res/drawable/item_background_borderless_quantum.xml
rename to core/res/res/drawable/item_background_borderless_material.xml
index c2a1c127..b730618 100644
--- a/core/res/res/drawable/item_background_borderless_quantum.xml
+++ b/core/res/res/drawable/item_background_borderless_material.xml
@@ -15,5 +15,4 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:tint="?attr/colorControlHighlight"
- android:pinned="true" />
+ android:color="?attr/colorControlHighlight" />
diff --git a/core/res/res/drawable/item_background_quantum.xml b/core/res/res/drawable/item_background_material.xml
similarity index 93%
rename from core/res/res/drawable/item_background_quantum.xml
rename to core/res/res/drawable/item_background_material.xml
index 039ca51..45ff181 100644
--- a/core/res/res/drawable/item_background_quantum.xml
+++ b/core/res/res/drawable/item_background_material.xml
@@ -15,8 +15,8 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:tint="?attr/colorControlHighlight">
+ android:color="?attr/colorControlHighlight">
<item android:id="@id/mask">
<color android:color="@color/white" />
</item>
-</ripple>
\ No newline at end of file
+</ripple>
diff --git a/core/res/res/drawable/list_divider_quantum.xml b/core/res/res/drawable/list_divider_material.xml
similarity index 93%
rename from core/res/res/drawable/list_divider_quantum.xml
rename to core/res/res/drawable/list_divider_material.xml
index e3d4ba2..bf24933 100644
--- a/core/res/res/drawable/list_divider_quantum.xml
+++ b/core/res/res/drawable/list_divider_material.xml
@@ -15,5 +15,5 @@
-->
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/list_divider_qntm_alpha"
+ android:src="@drawable/list_divider_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/list_divider_quantum.xml b/core/res/res/drawable/list_section_divider_material.xml
similarity index 92%
copy from core/res/res/drawable/list_divider_quantum.xml
copy to core/res/res/drawable/list_section_divider_material.xml
index e3d4ba2..515634e 100644
--- a/core/res/res/drawable/list_divider_quantum.xml
+++ b/core/res/res/drawable/list_section_divider_material.xml
@@ -15,5 +15,5 @@
-->
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/list_divider_qntm_alpha"
+ android:src="@drawable/list_section_divider_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/list_section_divider_quantum.xml b/core/res/res/drawable/list_section_divider_quantum.xml
deleted file mode 100644
index 87a1439..0000000
--- a/core/res/res/drawable/list_section_divider_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/list_section_divider_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/notification_bg_dim.xml b/core/res/res/drawable/notification_bg_dim.xml
index ae03d82..5c245f8 100644
--- a/core/res/res/drawable/notification_bg_dim.xml
+++ b/core/res/res/drawable/notification_bg_dim.xml
@@ -15,9 +15,7 @@
~ limitations under the License
-->
-<ripple
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:tint="#ff444444"
- >
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="#ff444444">
<item android:drawable="@drawable/notification_bg_normal" />
</ripple>
\ No newline at end of file
diff --git a/core/res/res/drawable/notification_quantum_bg.xml b/core/res/res/drawable/notification_material_bg.xml
similarity index 84%
rename from core/res/res/drawable/notification_quantum_bg.xml
rename to core/res/res/drawable/notification_material_bg.xml
index 300a565..44c67be 100644
--- a/core/res/res/drawable/notification_quantum_bg.xml
+++ b/core/res/res/drawable/notification_material_bg.xml
@@ -19,13 +19,13 @@
<item android:state_pressed="true">
<shape>
<solid android:color="#ffd0d0d0" />
- <corners android:radius="@dimen/notification_quantum_rounded_rect_radius" />
+ <corners android:radius="@dimen/notification_material_rounded_rect_radius" />
</shape>
</item>
<item>
<shape>
<solid android:color="#fffafafa" />
- <corners android:radius="@dimen/notification_quantum_rounded_rect_radius" />
+ <corners android:radius="@dimen/notification_material_rounded_rect_radius" />
</shape>
</item>
</selector>
\ No newline at end of file
diff --git a/core/res/res/drawable/notification_quantum_bg_dim.xml b/core/res/res/drawable/notification_material_bg_dim.xml
similarity index 65%
rename from core/res/res/drawable/notification_quantum_bg_dim.xml
rename to core/res/res/drawable/notification_material_bg_dim.xml
index eb9a4ab..9b691e6 100644
--- a/core/res/res/drawable/notification_quantum_bg_dim.xml
+++ b/core/res/res/drawable/notification_material_bg_dim.xml
@@ -15,15 +15,18 @@
~ limitations under the License
-->
-<ripple
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:tint="#ffffffff"
- android:tintMode="src_over"
- >
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/white">
<item>
<shape>
<solid android:color="#d4ffffff" />
- <corners android:radius="@dimen/notification_quantum_rounded_rect_radius" />
+ <corners android:radius="@dimen/notification_material_rounded_rect_radius" />
</shape>
</item>
-</ripple>
\ No newline at end of file
+ <item android:id="@id/mask">
+ <shape>
+ <solid android:color="@color/white" />
+ <corners android:radius="@dimen/notification_material_rounded_rect_radius" />
+ </shape>
+ </item>
+</ripple>
diff --git a/core/res/res/drawable/notification_quantum_media_progress.xml b/core/res/res/drawable/notification_material_media_progress.xml
similarity index 100%
rename from core/res/res/drawable/notification_quantum_media_progress.xml
rename to core/res/res/drawable/notification_material_media_progress.xml
diff --git a/core/res/res/drawable/popup_background_quantum.xml b/core/res/res/drawable/popup_background_material.xml
similarity index 93%
copy from core/res/res/drawable/popup_background_quantum.xml
copy to core/res/res/drawable/popup_background_material.xml
index a4d0291..9e50790 100644
--- a/core/res/res/drawable/popup_background_quantum.xml
+++ b/core/res/res/drawable/popup_background_material.xml
@@ -15,6 +15,6 @@
-->
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/popup_background_qntm_mult"
+ android:src="@drawable/popup_background_mtrl_mult"
android:tint="?attr/colorBackground"
android:tintMode="multiply" />
diff --git a/core/res/res/drawable/progress_horizontal_quantum.xml b/core/res/res/drawable/progress_horizontal_material.xml
similarity index 89%
rename from core/res/res/drawable/progress_horizontal_quantum.xml
rename to core/res/res/drawable/progress_horizontal_material.xml
index 1c2d494..eca1a24 100644
--- a/core/res/res/drawable/progress_horizontal_quantum.xml
+++ b/core/res/res/drawable/progress_horizontal_material.xml
@@ -16,18 +16,18 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@id/background">
- <nine-patch android:src="@drawable/progress_qntm_alpha"
+ <nine-patch android:src="@drawable/progress_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item android:id="@id/secondaryProgress">
<scale android:scaleWidth="100%">
- <nine-patch android:src="@drawable/progress_qntm_alpha"
+ <nine-patch android:src="@drawable/progress_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
</scale>
</item>
<item android:id="@id/progress">
<scale android:scaleWidth="100%">
- <nine-patch android:src="@drawable/progress_primary_qntm_alpha"
+ <nine-patch android:src="@drawable/progress_primary_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
</scale>
</item>
diff --git a/core/res/res/drawable/progress_large_quantum.xml b/core/res/res/drawable/progress_large_material.xml
similarity index 91%
rename from core/res/res/drawable/progress_large_quantum.xml
rename to core/res/res/drawable/progress_large_material.xml
index 7bef637..965b288 100644
--- a/core/res/res/drawable/progress_large_quantum.xml
+++ b/core/res/res/drawable/progress_large_material.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<quantum-progress xmlns:android="http://schemas.android.com/apk/res/android"
+<material-progress xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlActivated"
android:width="76dp"
android:height="76dp"
diff --git a/core/res/res/drawable/progress_medium_quantum.xml b/core/res/res/drawable/progress_medium_material.xml
similarity index 91%
rename from core/res/res/drawable/progress_medium_quantum.xml
rename to core/res/res/drawable/progress_medium_material.xml
index adc72f0..c656026 100644
--- a/core/res/res/drawable/progress_medium_quantum.xml
+++ b/core/res/res/drawable/progress_medium_material.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<quantum-progress xmlns:android="http://schemas.android.com/apk/res/android"
+<material-progress xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlActivated"
android:width="48dp"
android:height="48dp"
diff --git a/core/res/res/drawable/progress_small_quantum.xml b/core/res/res/drawable/progress_small_material.xml
similarity index 91%
rename from core/res/res/drawable/progress_small_quantum.xml
rename to core/res/res/drawable/progress_small_material.xml
index eb4884a..67ae268 100644
--- a/core/res/res/drawable/progress_small_quantum.xml
+++ b/core/res/res/drawable/progress_small_material.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<quantum-progress xmlns:android="http://schemas.android.com/apk/res/android"
+<material-progress xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlActivated"
android:width="16dp"
android:height="16dp"
diff --git a/core/res/res/drawable/ratingbar_full_empty_quantum.xml b/core/res/res/drawable/ratingbar_full_empty_material.xml
similarity index 87%
rename from core/res/res/drawable/ratingbar_full_empty_quantum.xml
rename to core/res/res/drawable/ratingbar_full_empty_material.xml
index e5e4315..a2ae7d9 100644
--- a/core/res/res/drawable/ratingbar_full_empty_quantum.xml
+++ b/core/res/res/drawable/ratingbar_full_empty_material.xml
@@ -16,11 +16,11 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
- <bitmap android:src="@drawable/btn_rating_star_off_qntm_alpha"
+ <bitmap android:src="@drawable/btn_rating_star_off_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item>
- <bitmap android:src="@drawable/btn_rating_star_off_qntm_alpha"
+ <bitmap android:src="@drawable/btn_rating_star_off_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
</selector>
diff --git a/core/res/res/drawable/ratingbar_full_filled_quantum.xml b/core/res/res/drawable/ratingbar_full_filled_material.xml
similarity index 87%
rename from core/res/res/drawable/ratingbar_full_filled_quantum.xml
rename to core/res/res/drawable/ratingbar_full_filled_material.xml
index ad3aa5d..801c85f 100644
--- a/core/res/res/drawable/ratingbar_full_filled_quantum.xml
+++ b/core/res/res/drawable/ratingbar_full_filled_material.xml
@@ -16,11 +16,11 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
- <bitmap android:src="@drawable/btn_rating_star_on_qntm_alpha"
+ <bitmap android:src="@drawable/btn_rating_star_on_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item>
- <bitmap android:src="@drawable/btn_rating_star_on_qntm_alpha"
+ <bitmap android:src="@drawable/btn_rating_star_on_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
</selector>
diff --git a/core/res/res/drawable/ratingbar_full_quantum.xml b/core/res/res/drawable/ratingbar_full_material.xml
similarity index 80%
rename from core/res/res/drawable/ratingbar_full_quantum.xml
rename to core/res/res/drawable/ratingbar_full_material.xml
index 143e7c2..122dd1d 100644
--- a/core/res/res/drawable/ratingbar_full_quantum.xml
+++ b/core/res/res/drawable/ratingbar_full_material.xml
@@ -16,9 +16,9 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@id/background"
- android:drawable="@drawable/ratingbar_full_empty_quantum" />
+ android:drawable="@drawable/ratingbar_full_empty_material" />
<item android:id="@id/secondaryProgress"
- android:drawable="@drawable/ratingbar_full_empty_quantum" />
+ android:drawable="@drawable/ratingbar_full_empty_material" />
<item android:id="@id/progress"
- android:drawable="@drawable/ratingbar_full_filled_quantum" />
+ android:drawable="@drawable/ratingbar_full_filled_material" />
</layer-list>
diff --git a/core/res/res/drawable/list_divider_quantum.xml b/core/res/res/drawable/scrollbar_handle_material.xml
similarity index 92%
copy from core/res/res/drawable/list_divider_quantum.xml
copy to core/res/res/drawable/scrollbar_handle_material.xml
index e3d4ba2..a241428 100644
--- a/core/res/res/drawable/list_divider_quantum.xml
+++ b/core/res/res/drawable/scrollbar_handle_material.xml
@@ -15,5 +15,5 @@
-->
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/list_divider_qntm_alpha"
+ android:src="@drawable/scrollbar_handle_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/scrollbar_handle_quantum.xml b/core/res/res/drawable/scrollbar_handle_quantum.xml
deleted file mode 100644
index f2de252..0000000
--- a/core/res/res/drawable/scrollbar_handle_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/scrollbar_handle_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/scrubber_control_quantum_anim.xml b/core/res/res/drawable/scrubber_control_material_anim.xml
similarity index 77%
rename from core/res/res/drawable/scrubber_control_quantum_anim.xml
rename to core/res/res/drawable/scrubber_control_material_anim.xml
index 87d3ae9..4b13259 100644
--- a/core/res/res/drawable/scrubber_control_quantum_anim.xml
+++ b/core/res/res/drawable/scrubber_control_material_anim.xml
@@ -16,58 +16,58 @@
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android" android:constantSize="true">
<item android:state_enabled="false" android:state_pressed="true">
- <bitmap android:src="@drawable/scrubber_control_off_qntm_alpha" android:gravity="center" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
+ <bitmap android:src="@drawable/scrubber_control_off_mtrl_alpha" android:gravity="center" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_enabled="false">
- <bitmap android:src="@drawable/scrubber_control_off_qntm_alpha" android:gravity="center" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" />
+ <bitmap android:src="@drawable/scrubber_control_off_mtrl_alpha" android:gravity="center" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_pressed="true" android:id="@+id/pressed">
- <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/scrubber_control_to_pressed_mtrl_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:id="@+id/not_pressed">
- <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/scrubber_control_to_pressed_mtrl_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<transition android:fromId="@+id/not_pressed" android:toId="@+id/pressed">
<animation-list>
<item android:duration="15">
- <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/scrubber_control_to_pressed_mtrl_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_001" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/scrubber_control_to_pressed_mtrl_001" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_002" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/scrubber_control_to_pressed_mtrl_002" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_003" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/scrubber_control_to_pressed_mtrl_003" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_004" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/scrubber_control_to_pressed_mtrl_004" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/scrubber_control_to_pressed_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/scrubber_control_to_pressed_mtrl_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
</animation-list>
</transition>
<transition android:fromId="@+id/pressed" android:toId="@+id/not_pressed">
<animation-list>
<item android:duration="15">
- <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/scrubber_control_from_pressed_mtrl_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_001" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/scrubber_control_from_pressed_mtrl_001" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_002" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/scrubber_control_from_pressed_mtrl_002" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_003" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/scrubber_control_from_pressed_mtrl_003" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_004" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/scrubber_control_from_pressed_mtrl_004" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/scrubber_control_from_pressed_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/scrubber_control_from_pressed_mtrl_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
</animation-list>
</transition>
diff --git a/core/res/res/drawable/scrubber_control_selector_quantum.xml b/core/res/res/drawable/scrubber_control_selector_material.xml
similarity index 87%
rename from core/res/res/drawable/scrubber_control_selector_quantum.xml
rename to core/res/res/drawable/scrubber_control_selector_material.xml
index ef3af0c..9892676 100644
--- a/core/res/res/drawable/scrubber_control_selector_quantum.xml
+++ b/core/res/res/drawable/scrubber_control_selector_material.xml
@@ -16,11 +16,11 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false">
- <bitmap android:src="@drawable/scrubber_control_off_qntm_alpha"
+ <bitmap android:src="@drawable/scrubber_control_off_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item>
- <bitmap android:src="@drawable/scrubber_control_on_qntm_alpha"
+ <bitmap android:src="@drawable/scrubber_control_on_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
</item>
</selector>
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml b/core/res/res/drawable/scrubber_progress_horizontal_material.xml
similarity index 93%
rename from core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
rename to core/res/res/drawable/scrubber_progress_horizontal_material.xml
index f82fe7a..f2ea30f 100644
--- a/core/res/res/drawable/scrubber_progress_horizontal_quantum.xml
+++ b/core/res/res/drawable/scrubber_progress_horizontal_material.xml
@@ -16,24 +16,24 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false">
- <nine-patch android:src="@drawable/scrubber_track_qntm_alpha"
+ <nine-patch android:src="@drawable/scrubber_track_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item>
<layer-list>
<item android:id="@id/background">
- <nine-patch android:src="@drawable/scrubber_track_qntm_alpha"
+ <nine-patch android:src="@drawable/scrubber_track_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item android:id="@id/secondaryProgress">
<scale android:scaleWidth="100%">
- <nine-patch android:src="@drawable/scrubber_primary_qntm_alpha"
+ <nine-patch android:src="@drawable/scrubber_primary_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</scale>
</item>
<item android:id="@id/progress">
<scale android:scaleWidth="100%">
- <nine-patch android:src="@drawable/scrubber_primary_qntm_alpha"
+ <nine-patch android:src="@drawable/scrubber_primary_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
</scale>
</item>
diff --git a/core/res/res/drawable/spinner_background_quantum.xml b/core/res/res/drawable/spinner_background_material.xml
similarity index 84%
rename from core/res/res/drawable/spinner_background_quantum.xml
rename to core/res/res/drawable/spinner_background_material.xml
index 727a78f..02ea11b 100644
--- a/core/res/res/drawable/spinner_background_quantum.xml
+++ b/core/res/res/drawable/spinner_background_material.xml
@@ -17,15 +17,15 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true">
<item android:state_checked="true">
- <nine-patch android:src="@drawable/spinner_qntm_am_alpha"
+ <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item android:state_pressed="true">
- <nine-patch android:src="@drawable/spinner_qntm_am_alpha"
+ <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item>
- <nine-patch android:src="@drawable/spinner_qntm_am_alpha"
+ <nine-patch android:src="@drawable/spinner_mtrl_am_alpha"
android:tint="?attr/colorControlNormal" />
</item>
</selector>
diff --git a/core/res/res/drawable/switch_thumb_quantum_anim.xml b/core/res/res/drawable/switch_thumb_material_anim.xml
similarity index 73%
rename from core/res/res/drawable/switch_thumb_quantum_anim.xml
rename to core/res/res/drawable/switch_thumb_material_anim.xml
index 1984d47..e7baa2c 100644
--- a/core/res/res/drawable/switch_thumb_quantum_anim.xml
+++ b/core/res/res/drawable/switch_thumb_material_anim.xml
@@ -16,112 +16,112 @@
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android" android:constantSize="true">
<item android:state_enabled="false" android:state_checked="true">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_014" android:gravity="center" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_014" android:gravity="center" android:tint="?attr/colorControlActivated" android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_enabled="false">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_000" android:gravity="center" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_000" android:gravity="center" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_checked="true" android:id="@+id/on">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_014" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_014" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:id="@+id/off">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_000" android:gravity="center" android:tint="?attr/colorControlNormal" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_000" android:gravity="center" 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_switch_to_on_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_001" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_001" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_002" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_002" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_003" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_003" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_004" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_004" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_006" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_006" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_007" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_007" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_008" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_008" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_009" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_009" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_010" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_010" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_011" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_011" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_012" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_012" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_013" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_013" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_on_qntm_014" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_on_mtrl_014" android:gravity="center" 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_switch_to_off_qntm_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_000" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_off_qntm_001" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_001" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_off_qntm_002" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_002" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_off_qntm_003" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_003" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_off_qntm_004" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_004" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_off_qntm_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_005" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_off_qntm_006" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_006" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_off_qntm_007" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_007" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_off_qntm_008" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_008" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_off_qntm_009" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_009" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_off_qntm_010" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_010" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_off_qntm_011" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_011" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_off_qntm_012" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_012" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_off_qntm_013" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_013" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <bitmap android:src="@drawable/btn_switch_to_off_qntm_014" android:gravity="center" android:tint="?attr/colorControlActivated" />
+ <bitmap android:src="@drawable/btn_switch_to_off_mtrl_014" android:gravity="center" android:tint="?attr/colorControlActivated" />
</item>
</animation-list>
</transition>
diff --git a/core/res/res/drawable/switch_track_quantum.xml b/core/res/res/drawable/switch_track_material.xml
similarity index 83%
rename from core/res/res/drawable/switch_track_quantum.xml
rename to core/res/res/drawable/switch_track_material.xml
index 3651a0a..6ca2489 100644
--- a/core/res/res/drawable/switch_track_quantum.xml
+++ b/core/res/res/drawable/switch_track_material.xml
@@ -16,21 +16,21 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:state_checked="true">
- <nine-patch android:src="@drawable/switch_track_qntm_alpha"
+ <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
android:tint="?attr/colorControlActivated"
android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_enabled="false">
- <nine-patch android:src="@drawable/switch_track_qntm_alpha"
+ <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
android:tint="?attr/colorControlNormal"
android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_checked="true">
- <nine-patch android:src="@drawable/switch_track_qntm_alpha"
+ <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item>
- <nine-patch android:src="@drawable/switch_track_qntm_alpha"
+ <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
</selector>
diff --git a/core/res/res/drawable/tab_indicator_quantum.xml b/core/res/res/drawable/tab_indicator_material.xml
similarity index 93%
rename from core/res/res/drawable/tab_indicator_quantum.xml
rename to core/res/res/drawable/tab_indicator_material.xml
index ff14d9c..16362c0 100644
--- a/core/res/res/drawable/tab_indicator_quantum.xml
+++ b/core/res/res/drawable/tab_indicator_material.xml
@@ -16,7 +16,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
- <nine-patch android:src="@drawable/tab_indicator_qntm_alpha"
+ <nine-patch android:src="@drawable/tab_indicator_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item android:drawable="@color/transparent" />
diff --git a/core/res/res/drawable/text_cursor_quantum.xml b/core/res/res/drawable/text_cursor_material.xml
similarity index 93%
rename from core/res/res/drawable/text_cursor_quantum.xml
rename to core/res/res/drawable/text_cursor_material.xml
index 23d4ae0..a350c47 100644
--- a/core/res/res/drawable/text_cursor_quantum.xml
+++ b/core/res/res/drawable/text_cursor_material.xml
@@ -15,5 +15,5 @@
-->
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/text_cursor_qntm_alpha"
+ android:src="@drawable/text_cursor_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
diff --git a/core/res/res/drawable/text_select_handle_right_quantum.xml b/core/res/res/drawable/text_select_handle_left_material.xml
similarity index 92%
rename from core/res/res/drawable/text_select_handle_right_quantum.xml
rename to core/res/res/drawable/text_select_handle_left_material.xml
index 413661f..b228d3f 100644
--- a/core/res/res/drawable/text_select_handle_right_quantum.xml
+++ b/core/res/res/drawable/text_select_handle_left_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/text_select_handle_right_qntm_alpha"
+ android:src="@drawable/text_select_handle_left_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
diff --git a/core/res/res/drawable/text_select_handle_left_quantum.xml b/core/res/res/drawable/text_select_handle_left_quantum.xml
deleted file mode 100644
index a0ad7cf..0000000
--- a/core/res/res/drawable/text_select_handle_left_quantum.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/text_select_handle_left_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
diff --git a/core/res/res/drawable/text_select_handle_middle_quantum.xml b/core/res/res/drawable/text_select_handle_middle_material.xml
similarity index 92%
rename from core/res/res/drawable/text_select_handle_middle_quantum.xml
rename to core/res/res/drawable/text_select_handle_middle_material.xml
index bff0b66..f0f4b3e 100644
--- a/core/res/res/drawable/text_select_handle_middle_quantum.xml
+++ b/core/res/res/drawable/text_select_handle_middle_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/text_select_handle_middle_qntm_alpha"
+ android:src="@drawable/text_select_handle_middle_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
diff --git a/core/res/res/drawable/text_select_handle_right_quantum.xml b/core/res/res/drawable/text_select_handle_right_material.xml
similarity index 92%
copy from core/res/res/drawable/text_select_handle_right_quantum.xml
copy to core/res/res/drawable/text_select_handle_right_material.xml
index 413661f..acacbf6 100644
--- a/core/res/res/drawable/text_select_handle_right_quantum.xml
+++ b/core/res/res/drawable/text_select_handle_right_material.xml
@@ -15,5 +15,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/text_select_handle_right_qntm_alpha"
+ android:src="@drawable/text_select_handle_right_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
diff --git a/core/res/res/drawable/textfield_search_quantum.xml b/core/res/res/drawable/textfield_search_material.xml
similarity index 94%
rename from core/res/res/drawable/textfield_search_quantum.xml
rename to core/res/res/drawable/textfield_search_material.xml
index 877de46..1c0f5eb 100644
--- a/core/res/res/drawable/textfield_search_quantum.xml
+++ b/core/res/res/drawable/textfield_search_material.xml
@@ -16,27 +16,27 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:state_enabled="true">
- <nine-patch android:src="@drawable/textfield_search_default_qntm_alpha"
+ <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item android:state_window_focused="false" android:state_enabled="false">
- <nine-patch android:src="@drawable/textfield_search_default_qntm_alpha"
+ <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item android:state_enabled="true" android:state_focused="true">
- <nine-patch android:src="@drawable/textfield_search_activated_qntm_alpha"
+ <nine-patch android:src="@drawable/textfield_search_activated_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item android:state_enabled="true" android:state_activated="true">
- <nine-patch android:src="@drawable/textfield_search_activated_qntm_alpha"
+ <nine-patch android:src="@drawable/textfield_search_activated_mtrl_alpha"
android:tint="?attr/colorControlActivated" />
</item>
<item android:state_enabled="true">
- <nine-patch android:src="@drawable/textfield_search_default_qntm_alpha"
+ <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
<item>
- <nine-patch android:src="@drawable/textfield_search_default_qntm_alpha"
+ <nine-patch android:src="@drawable/textfield_search_default_mtrl_alpha"
android:tint="?attr/colorControlNormal" />
</item>
</selector>
diff --git a/core/res/res/interpolator/accelerate_quart.xml b/core/res/res/interpolator/accelerate_quart.xml
new file mode 100644
index 0000000..64efec6
--- /dev/null
+++ b/core/res/res/interpolator/accelerate_quart.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<accelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:factor="2.0" />
diff --git a/core/res/res/interpolator/decelerate_quart.xml b/core/res/res/interpolator/decelerate_quart.xml
new file mode 100644
index 0000000..9f6a51f
--- /dev/null
+++ b/core/res/res/interpolator/decelerate_quart.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<decelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:factor="2.0" />
diff --git a/core/res/res/layout/action_bar_home_quantum.xml b/core/res/res/layout/action_bar_home_material.xml
similarity index 100%
rename from core/res/res/layout/action_bar_home_quantum.xml
rename to core/res/res/layout/action_bar_home_material.xml
diff --git a/core/res/res/layout/alert_dialog_quantum.xml b/core/res/res/layout/alert_dialog_material.xml
similarity index 98%
rename from core/res/res/layout/alert_dialog_quantum.xml
rename to core/res/res/layout/alert_dialog_material.xml
index 7fd22ad..57bdfc9 100644
--- a/core/res/res/layout/alert_dialog_quantum.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -21,7 +21,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:background="@drawable/dialog_background_quantum"
+ android:background="@drawable/dialog_background_material"
android:translationZ="@dimen/floating_window_z"
android:layout_marginLeft="@dimen/floating_window_margin_left"
android:layout_marginTop="@dimen/floating_window_margin_top"
diff --git a/core/res/res/layout/alert_dialog_progress_quantum.xml b/core/res/res/layout/alert_dialog_progress_material.xml
similarity index 100%
rename from core/res/res/layout/alert_dialog_progress_quantum.xml
rename to core/res/res/layout/alert_dialog_progress_material.xml
diff --git a/core/res/res/layout/dialog_custom_title_quantum.xml b/core/res/res/layout/dialog_custom_title_material.xml
similarity index 95%
rename from core/res/res/layout/dialog_custom_title_quantum.xml
rename to core/res/res/layout/dialog_custom_title_material.xml
index 1bb93eb..550b72e 100644
--- a/core/res/res/layout/dialog_custom_title_quantum.xml
+++ b/core/res/res/layout/dialog_custom_title_material.xml
@@ -23,6 +23,7 @@
android:fitsSystemWindows="true">
<FrameLayout android:id="@android:id/title_container"
android:layout_width="match_parent"
+ android:layout_height="?android:attr/windowTitleSize"
android:layout_weight="0"
android:gravity="center_vertical|start"
style="?android:attr/windowTitleBackgroundStyle" />
diff --git a/core/res/res/layout/dialog_title_icons_quantum.xml b/core/res/res/layout/dialog_title_icons_material.xml
similarity index 100%
rename from core/res/res/layout/dialog_title_icons_quantum.xml
rename to core/res/res/layout/dialog_title_icons_material.xml
diff --git a/core/res/res/layout/dialog_title_quantum.xml b/core/res/res/layout/dialog_title_material.xml
similarity index 97%
rename from core/res/res/layout/dialog_title_quantum.xml
rename to core/res/res/layout/dialog_title_material.xml
index b92c1e7..918c8f1 100644
--- a/core/res/res/layout/dialog_title_quantum.xml
+++ b/core/res/res/layout/dialog_title_material.xml
@@ -22,7 +22,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:fitsSystemWindows="true">
- <TextView android:id="@+id/alertTitle"
+ <TextView android:id="@+id/title"
style="?android:attr/windowTitleStyle"
android:singleLine="true"
android:ellipsize="end"
diff --git a/core/res/res/layout/notification_quantum_action.xml b/core/res/res/layout/notification_material_action.xml
similarity index 93%
rename from core/res/res/layout/notification_quantum_action.xml
rename to core/res/res/layout/notification_material_action.xml
index 0986343..7ccaad5 100644
--- a/core/res/res/layout/notification_quantum_action.xml
+++ b/core/res/res/layout/notification_material_action.xml
@@ -16,7 +16,7 @@
-->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
- style="@android:style/Widget.Quantum.Light.Button.Borderless.Small"
+ style="@android:style/Widget.Material.Light.Button.Borderless.Small"
android:id="@+id/action0"
android:layout_width="0dp"
android:layout_height="48dp"
diff --git a/core/res/res/layout/notification_quantum_action_list.xml b/core/res/res/layout/notification_material_action_list.xml
similarity index 100%
rename from core/res/res/layout/notification_quantum_action_list.xml
rename to core/res/res/layout/notification_material_action_list.xml
diff --git a/core/res/res/layout/notification_quantum_action_tombstone.xml b/core/res/res/layout/notification_material_action_tombstone.xml
similarity index 93%
rename from core/res/res/layout/notification_quantum_action_tombstone.xml
rename to core/res/res/layout/notification_material_action_tombstone.xml
index 51e4205..8bf456e 100644
--- a/core/res/res/layout/notification_quantum_action_tombstone.xml
+++ b/core/res/res/layout/notification_material_action_tombstone.xml
@@ -16,7 +16,7 @@
-->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
- style="@android:style/Widget.Quantum.Light.Button.Borderless.Small"
+ style="@android:style/Widget.Material.Light.Button.Borderless.Small"
android:id="@+id/action0"
android:layout_width="0dp"
android:layout_height="48dp"
diff --git a/core/res/res/layout/notification_quantum_media_action.xml b/core/res/res/layout/notification_material_media_action.xml
similarity index 92%
rename from core/res/res/layout/notification_quantum_media_action.xml
rename to core/res/res/layout/notification_material_media_action.xml
index 17f0848..331ee57 100644
--- a/core/res/res/layout/notification_quantum_media_action.xml
+++ b/core/res/res/layout/notification_material_media_action.xml
@@ -16,7 +16,7 @@
-->
<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
- style="@android:style/Widget.Quantum.Light.Button.Borderless.Small"
+ style="@android:style/Widget.Material.Light.Button.Borderless.Small"
android:id="@+id/action0"
android:layout_width="60dp"
android:layout_height="match_parent"
diff --git a/core/res/res/layout/notification_template_quantum_base.xml b/core/res/res/layout/notification_template_material_base.xml
similarity index 96%
rename from core/res/res/layout/notification_template_quantum_base.xml
rename to core/res/res/layout/notification_template_material_base.xml
index 4265f9d..ab13b98 100644
--- a/core/res/res/layout/notification_template_quantum_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -49,7 +49,7 @@
android:orientation="horizontal"
>
<TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Title"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
@@ -73,7 +73,7 @@
/>
</LinearLayout>
<TextView android:id="@+id/text2"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Line2"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Line2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-2dp"
@@ -90,7 +90,7 @@
android:layout_height="12dp"
android:layout_marginStart="8dp"
android:visibility="gone"
- style="@style/Widget.StatusBar.Quantum.ProgressBar"
+ style="@style/Widget.StatusBar.Material.ProgressBar"
/>
<LinearLayout
android:id="@+id/line3"
@@ -101,7 +101,7 @@
android:layout_marginStart="8dp"
>
<TextView android:id="@+id/text"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
@@ -111,7 +111,7 @@
android:fadingEdge="horizontal"
/>
<TextView android:id="@+id/info"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Info"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
diff --git a/core/res/res/layout/notification_template_quantum_big_base.xml b/core/res/res/layout/notification_template_material_big_base.xml
similarity index 95%
rename from core/res/res/layout/notification_template_quantum_big_base.xml
rename to core/res/res/layout/notification_template_material_big_base.xml
index 95a4c82..0564a8f 100644
--- a/core/res/res/layout/notification_template_quantum_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -53,7 +53,7 @@
android:orientation="horizontal"
>
<TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Title"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
@@ -77,7 +77,7 @@
/>
</LinearLayout>
<TextView android:id="@+id/text2"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Line2"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Line2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-2dp"
@@ -90,7 +90,7 @@
android:visibility="gone"
/>
<TextView android:id="@+id/big_text"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
@@ -108,7 +108,7 @@
android:gravity="center_vertical"
>
<TextView android:id="@+id/text"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
@@ -118,7 +118,7 @@
android:fadingEdge="horizontal"
/>
<TextView android:id="@+id/info"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Info"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
@@ -145,7 +145,7 @@
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:visibility="gone"
- style="@style/Widget.Quantum.Light.ProgressBar.Horizontal"
+ style="@style/Widget.StatusBar.Material.ProgressBar"
/>
</LinearLayout>
<ImageView
@@ -155,7 +155,7 @@
android:visibility="gone"
android:background="@drawable/list_divider_holo_light" />
<include
- layout="@layout/notification_quantum_action_list"
+ layout="@layout/notification_material_action_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/notification_large_icon_width"
diff --git a/core/res/res/layout/notification_template_quantum_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
similarity index 95%
rename from core/res/res/layout/notification_template_quantum_big_media.xml
rename to core/res/res/layout/notification_template_material_big_media.xml
index 5c9334e..f8e1986 100644
--- a/core/res/res/layout/notification_template_quantum_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -38,7 +38,6 @@
android:minHeight="@dimen/notification_large_icon_height"
android:paddingTop="2dp"
android:orientation="vertical"
- android:background="@color/notification_media_info_bg"
>
<LinearLayout
android:id="@+id/line1"
@@ -50,7 +49,7 @@
android:orientation="horizontal"
>
<TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Title"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
@@ -74,7 +73,7 @@
/>
</LinearLayout>
<TextView android:id="@+id/text2"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Line2"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Line2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-2dp"
@@ -87,7 +86,7 @@
android:visibility="gone"
/>
<TextView android:id="@+id/big_text"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
@@ -105,7 +104,7 @@
android:gravity="center_vertical"
>
<TextView android:id="@+id/text"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
@@ -115,7 +114,7 @@
android:fadingEdge="horizontal"
/>
<TextView android:id="@+id/info"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Info"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
@@ -147,7 +146,7 @@
android:layout_height="6dp"
android:layout_gravity="top"
android:visibility="gone"
- style="@style/Widget.StatusBar.Quantum.ProgressBar"
+ style="@style/Widget.StatusBar.Material.ProgressBar.Media"
/>
</FrameLayout>
</LinearLayout>
diff --git a/core/res/res/layout/notification_template_quantum_big_picture.xml b/core/res/res/layout/notification_template_material_big_picture.xml
similarity index 94%
rename from core/res/res/layout/notification_template_quantum_big_picture.xml
rename to core/res/res/layout/notification_template_material_big_picture.xml
index f68e414..74819fd 100644
--- a/core/res/res/layout/notification_template_quantum_big_picture.xml
+++ b/core/res/res/layout/notification_template_material_big_picture.xml
@@ -38,7 +38,7 @@
android:scaleType="fitXY"
android:src="@drawable/title_bar_shadow"
/>
- <include layout="@layout/notification_template_quantum_base"
+ <include layout="@layout/notification_template_material_base"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
@@ -51,7 +51,7 @@
android:background="#CCEEEEEE"
>
<include
- layout="@layout/notification_quantum_action_list"
+ layout="@layout/notification_material_action_list"
android:id="@+id/actions"
android:layout_gravity="bottom"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_template_quantum_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
similarity index 95%
rename from core/res/res/layout/notification_template_quantum_big_text.xml
rename to core/res/res/layout/notification_template_material_big_text.xml
index 45811fc..1de5add 100644
--- a/core/res/res/layout/notification_template_quantum_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -55,7 +55,7 @@
android:layout_weight="0"
>
<TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Title"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
@@ -79,7 +79,7 @@
/>
</LinearLayout>
<TextView android:id="@+id/text2"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Line2"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Line2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-2dp"
@@ -99,10 +99,10 @@
android:layout_marginEnd="8dp"
android:visibility="gone"
android:layout_weight="0"
- style="@style/Widget.Quantum.Light.ProgressBar.Horizontal"
+ style="@style/Widget.StatusBar.Material.ProgressBar"
/>
<TextView android:id="@+id/big_text"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="10dp"
@@ -121,7 +121,7 @@
android:visibility="gone"
android:background="@drawable/list_divider_holo_light" />
<include
- layout="@layout/notification_quantum_action_list"
+ layout="@layout/notification_material_action_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="gone"
@@ -146,7 +146,7 @@
android:gravity="center_vertical"
>
<TextView android:id="@+id/text"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
@@ -156,7 +156,7 @@
android:fadingEdge="horizontal"
/>
<TextView android:id="@+id/info"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Info"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
diff --git a/core/res/res/layout/notification_template_quantum_inbox.xml b/core/res/res/layout/notification_template_material_inbox.xml
similarity index 95%
rename from core/res/res/layout/notification_template_quantum_inbox.xml
rename to core/res/res/layout/notification_template_material_inbox.xml
index 3851dd3..8411ff5 100644
--- a/core/res/res/layout/notification_template_quantum_inbox.xml
+++ b/core/res/res/layout/notification_template_material_inbox.xml
@@ -56,7 +56,7 @@
android:layout_weight="0"
>
<TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Title"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
@@ -80,7 +80,7 @@
/>
</LinearLayout>
<TextView android:id="@+id/text2"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Line2"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Line2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-2dp"
@@ -101,10 +101,10 @@
android:layout_marginEnd="8dp"
android:visibility="gone"
android:layout_weight="0"
- style="@style/Widget.Quantum.Light.ProgressBar.Horizontal"
+ style="@style/Widget.Material.Light.ProgressBar.Horizontal"
/>
<TextView android:id="@+id/inbox_text0"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="8dp"
@@ -115,7 +115,7 @@
android:layout_weight="1"
/>
<TextView android:id="@+id/inbox_text1"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="8dp"
@@ -126,7 +126,7 @@
android:layout_weight="1"
/>
<TextView android:id="@+id/inbox_text2"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="8dp"
@@ -137,7 +137,7 @@
android:layout_weight="1"
/>
<TextView android:id="@+id/inbox_text3"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="8dp"
@@ -148,7 +148,7 @@
android:layout_weight="1"
/>
<TextView android:id="@+id/inbox_text4"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="8dp"
@@ -158,7 +158,7 @@
android:layout_weight="1"
/>
<TextView android:id="@+id/inbox_text5"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="8dp"
@@ -169,7 +169,7 @@
android:layout_weight="1"
/>
<TextView android:id="@+id/inbox_text6"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="8dp"
@@ -180,7 +180,7 @@
android:layout_weight="1"
/>
<TextView android:id="@+id/inbox_more"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="8dp"
@@ -206,7 +206,7 @@
android:visibility="gone"
android:background="@drawable/list_divider_holo_light" />
<include
- layout="@layout/notification_quantum_action_list"
+ layout="@layout/notification_material_action_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
@@ -230,7 +230,7 @@
android:gravity="center_vertical"
>
<TextView android:id="@+id/text"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
@@ -240,7 +240,7 @@
android:fadingEdge="horizontal"
/>
<TextView android:id="@+id/info"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Info"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
diff --git a/core/res/res/layout/notification_template_quantum_media.xml b/core/res/res/layout/notification_template_material_media.xml
similarity index 96%
rename from core/res/res/layout/notification_template_quantum_media.xml
rename to core/res/res/layout/notification_template_material_media.xml
index 14fabce..c2fc006 100644
--- a/core/res/res/layout/notification_template_quantum_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -50,7 +50,7 @@
android:orientation="horizontal"
>
<TextView android:id="@+id/title"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Title"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
@@ -74,7 +74,7 @@
/>
</LinearLayout>
<TextView android:id="@+id/text2"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Line2"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Line2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-2dp"
@@ -91,7 +91,7 @@
android:layout_height="12dp"
android:layout_marginStart="8dp"
android:visibility="gone"
- style="@style/Widget.StatusBar.Quantum.ProgressBar"
+ style="@style/Widget.StatusBar.Material.ProgressBar"
/>
<LinearLayout
android:id="@+id/line3"
@@ -102,7 +102,7 @@
android:layout_marginStart="8dp"
>
<TextView android:id="@+id/text"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
@@ -112,7 +112,7 @@
android:fadingEdge="horizontal"
/>
<TextView android:id="@+id/info"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Info"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
diff --git a/core/res/res/layout/notification_template_part_chronometer.xml b/core/res/res/layout/notification_template_part_chronometer.xml
index 9b6e6c5..87dfe1f 100644
--- a/core/res/res/layout/notification_template_part_chronometer.xml
+++ b/core/res/res/layout/notification_template_part_chronometer.xml
@@ -15,7 +15,7 @@
-->
<Chronometer android:id="@+id/chronometer" xmlns:android="http://schemas.android.com/apk/res/android"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Time"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
diff --git a/core/res/res/layout/notification_template_part_time.xml b/core/res/res/layout/notification_template_part_time.xml
index b559dce..5982c48 100644
--- a/core/res/res/layout/notification_template_part_time.xml
+++ b/core/res/res/layout/notification_template_part_time.xml
@@ -15,7 +15,7 @@
-->
<DateTimeView android:id="@+id/time" xmlns:android="http://schemas.android.com/apk/res/android"
- android:textAppearance="@style/TextAppearance.StatusBar.Quantum.EventContent.Time"
+ android:textAppearance="@style/TextAppearance.StatusBar.Material.EventContent.Time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
diff --git a/core/res/res/layout/preference_category_quantum.xml b/core/res/res/layout/preference_category_material.xml
similarity index 94%
rename from core/res/res/layout/preference_category_quantum.xml
rename to core/res/res/layout/preference_category_material.xml
index 9dd0d86..456b252 100644
--- a/core/res/res/layout/preference_category_quantum.xml
+++ b/core/res/res/layout/preference_category_material.xml
@@ -20,7 +20,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dip"
- android:textAppearance="@style/TextAppearance.Quantum.Body2"
+ android:textAppearance="@style/TextAppearance.Material.Body2"
android:textColor="?android:attr/colorAccent"
android:paddingStart="?attr/listPreferredItemPaddingStart"
android:paddingEnd="?attr/listPreferredItemPaddingEnd"
diff --git a/core/res/res/layout/preference_child_quantum.xml b/core/res/res/layout/preference_child_material.xml
similarity index 100%
rename from core/res/res/layout/preference_child_quantum.xml
rename to core/res/res/layout/preference_child_material.xml
diff --git a/core/res/res/layout/preference_information_quantum.xml b/core/res/res/layout/preference_information_material.xml
similarity index 100%
rename from core/res/res/layout/preference_information_quantum.xml
rename to core/res/res/layout/preference_information_material.xml
diff --git a/core/res/res/layout/preference_quantum.xml b/core/res/res/layout/preference_material.xml
similarity index 98%
rename from core/res/res/layout/preference_quantum.xml
rename to core/res/res/layout/preference_material.xml
index a4fe73d..a9599139 100644
--- a/core/res/res/layout/preference_quantum.xml
+++ b/core/res/res/layout/preference_material.xml
@@ -31,7 +31,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="58dip"
- android:gravity="left|center_vertical"
+ android:gravity="start|center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+android:id/icon"
diff --git a/core/res/res/layout/preference_widget_checkbox.xml b/core/res/res/layout/preference_widget_checkbox.xml
index bfd7f0a..f794346 100644
--- a/core/res/res/layout/preference_widget_checkbox.xml
+++ b/core/res/res/layout/preference_widget_checkbox.xml
@@ -21,4 +21,5 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
- android:clickable="false" />
+ android:clickable="false"
+ android:background="@null" />
diff --git a/core/res/res/layout/preference_widget_seekbar.xml b/core/res/res/layout/preference_widget_seekbar.xml
index c427965..05daa1a 100644
--- a/core/res/res/layout/preference_widget_seekbar.xml
+++ b/core/res/res/layout/preference_widget_seekbar.xml
@@ -14,9 +14,7 @@
limitations under the License.
-->
-<!-- Layout for a Preference in a PreferenceActivity. The
- Preference is able to place a specific widget for its particular
- type in the "widget_frame" layout. -->
+<!-- Layout used by SeekBarPreference for the seekbar widget style. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/core/res/res/layout/preference_widget_seekbar_material.xml b/core/res/res/layout/preference_widget_seekbar_material.xml
new file mode 100644
index 0000000..f70a472
--- /dev/null
+++ b/core/res/res/layout/preference_widget_seekbar_material.xml
@@ -0,0 +1,86 @@
+<?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.
+-->
+
+<!-- Layout used by SeekBarPreference for the seekbar widget style. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:paddingStart="?attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?attr/listPreferredItemPaddingEnd">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:minWidth="@dimen/preference_icon_minWidth"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:minWidth="48dp"
+ />
+ </LinearLayout>
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="8dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_weight="1">
+
+ <TextView android:id="@+android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <TextView android:id="@+android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_alignStart="@android:id/title"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="4" />
+
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout android:id="@+android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_below="@android:id/summary"
+ android:layout_alignStart="@android:id/title"
+ android:minWidth="@dimen/preference_widget_width"
+ android:gravity="center"
+ android:orientation="vertical" />
+
+ <SeekBar android:id="@+android:id/seekbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/summary"
+ android:layout_toEndOf="@android:id/widget_frame"
+ android:layout_alignParentEnd="true" />
+
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/core/res/res/layout/preference_widget_switch.xml b/core/res/res/layout/preference_widget_switch.xml
index 534c7ec..04a310b 100644
--- a/core/res/res/layout/preference_widget_switch.xml
+++ b/core/res/res/layout/preference_widget_switch.xml
@@ -21,4 +21,5 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dip"
- android:focusable="false" />
+ android:focusable="false"
+ android:background="@null" />
diff --git a/core/res/res/layout/progress_dialog_quantum.xml b/core/res/res/layout/progress_dialog_material.xml
similarity index 100%
rename from core/res/res/layout/progress_dialog_quantum.xml
rename to core/res/res/layout/progress_dialog_material.xml
diff --git a/core/res/res/layout/select_dialog_item_quantum.xml b/core/res/res/layout/select_dialog_item_material.xml
similarity index 100%
rename from core/res/res/layout/select_dialog_item_quantum.xml
rename to core/res/res/layout/select_dialog_item_material.xml
diff --git a/core/res/res/layout/select_dialog_quantum.xml b/core/res/res/layout/select_dialog_material.xml
similarity index 100%
rename from core/res/res/layout/select_dialog_quantum.xml
rename to core/res/res/layout/select_dialog_material.xml
diff --git a/core/res/res/layout/select_dialog_multichoice_quantum.xml b/core/res/res/layout/select_dialog_multichoice_material.xml
similarity index 100%
rename from core/res/res/layout/select_dialog_multichoice_quantum.xml
rename to core/res/res/layout/select_dialog_multichoice_material.xml
diff --git a/core/res/res/layout/select_dialog_singlechoice_quantum.xml b/core/res/res/layout/select_dialog_singlechoice_material.xml
similarity index 100%
rename from core/res/res/layout/select_dialog_singlechoice_quantum.xml
rename to core/res/res/layout/select_dialog_singlechoice_material.xml
diff --git a/core/res/res/layout/status_bar_latest_event_content.xml b/core/res/res/layout/status_bar_latest_event_content.xml
index dc78174..9444164 100644
--- a/core/res/res/layout/status_bar_latest_event_content.xml
+++ b/core/res/res/layout/status_bar_latest_event_content.xml
@@ -22,7 +22,7 @@
android:layout_height="wrap_content"
android:background="#FFFF00FF"
>
- <include layout="@layout/notification_template_quantum_base"
+ <include layout="@layout/notification_template_material_base"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
diff --git a/core/res/res/layout/subscription_item_layout.xml b/core/res/res/layout/subscription_item_layout.xml
new file mode 100755
index 0000000..9f8f2b3
--- /dev/null
+++ b/core/res/res/layout/subscription_item_layout.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright (C) 2014 MediaTek Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" >
+ <RelativeLayout
+ android:layout_width="48dip"
+ android:layout_height="32dip"
+ android:id="@+id/sub_color"
+ android:layout_marginEnd="6dip"
+ android:layout_centerVertical="true">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/sub_short_number"
+ android:layout_marginBottom="2dip"
+ android:layout_marginEnd="4dip"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentBottom="true"
+ android:textSize="12sp"
+ android:singleLine="true"
+ android:textColor="@android:color/white"
+ android:includeFontPadding="false"/>
+ </RelativeLayout>
+ <RelativeLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_centerVertical="true">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/sub_name"
+ android:singleLine="true"
+ android:ellipsize="none"
+ android:requiresFadingEdge="horizontal"
+ android:scrollHorizontally="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/sub_number"
+ android:layout_below="@+id/sub_name"
+ android:layout_alignStart="@+id/sub_name"
+ android:singleLine="true"
+ android:ellipsize="none"
+ android:requiresFadingEdge="horizontal"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"/>
+ </RelativeLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/tab_indicator_quantum.xml b/core/res/res/layout/tab_indicator_material.xml
similarity index 92%
rename from core/res/res/layout/tab_indicator_quantum.xml
rename to core/res/res/layout/tab_indicator_material.xml
index fcb2d5f..7dba219 100644
--- a/core/res/res/layout/tab_indicator_quantum.xml
+++ b/core/res/res/layout/tab_indicator_material.xml
@@ -18,7 +18,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="?android:attr/actionBarSize"
android:orientation="horizontal"
- style="@android:style/Widget.Quantum.Tab">
+ style="@android:style/Widget.Material.Tab">
<ImageView
android:id="@android:id/icon"
@@ -32,6 +32,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- style="@android:style/Widget.Quantum.TabText" />
+ style="@android:style/Widget.Material.TabText" />
</LinearLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 21f1401..72b0909 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-stelsel"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Persoonlik"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Werk"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Persoonlike programme"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Werk"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Dienste wat jou geld kos"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Doen dinge wat jou geld kan kos."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Jou boodskappe"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n muurpapier te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"verbind met \'n steminteraksiediens"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Laat die houer toe om met die topvlak-koppelvlak van \'n steminteraksiediens te verbind. Behoort nooit vir normale programme nodig te wees nie."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"bestuur stemsleutelfrases"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Laat die houer toe om die sleutelfrases vir aktiveerwoordbespeuring met stem te bestuur. Behoort nooit vir normale programme nodig te wees nie."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"koppel aan \'n afstandskerm"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Dit laat die houer toe om aan die top-koppelvlak van \'n afstandskerm te koppel. Behoort nooit vir gewone programme nodig te wees nie."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind aan \'n legstukdiens"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Laat die program toe om enige geïnstalleer mediadekodeerder te gebruik om te kan dekodeer vir terugspeel."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"bestuur vertroude eiebewyse"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Laat die program CA-sertifikate as vertroude eiebewyse installeer en deïnstalleer."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"laat program gedurende ledige tyd loop"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Met hierdie toestemming kan die Android-stelsel die program in die agtergrond laat loop terwyl die toestel nie gebruik word nie."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"laat loop die program se geskeduleerde agtergrondwerk"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Hierdie toestemming laat die Android-stelsel toe om die program in die agtergrond te laat loop wanneer dit versoek word."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lees/skryf na bronne wat diag besit"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Laat die program toe om na enige hulpbron wat deur die diag-groep besit word, te skryf, byvoorbeeld lêers in /dev. Dit kan potensieel stelselstabiliteit en sekuriteit affekteer. Dit moet NET gebruik word vir hardewarespesifieke diagnose deur die vervaardiger of operateur."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktiveer of deaktiveer programkomponente"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Laat die program oudio-uitset vasvang en herlei."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Aktiveerwoord-opsporing"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Laat die program toe om oudio vir Aktiveerwoord-opsporing op te neem. Die opname kan in die agtergrond plaasvind, maar verhoed nie dat ander oudio opgeneem word nie (bv. Kameraopnemer)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Oudio-versending"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Laat die program toe om oudio-versending direk te beheer en oudio-beleidsbesluite ter syde te stel."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"vang video-uitset vas"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Laat die program video-uitset vasvang en herlei."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"vang veilige video-uitset vas"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Laat \'n program toe om keyguard te beheer."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Luister na vertrouenstaatveranderinge."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Laat \'n program toe om vir veranderinge in vertrouenstaat te luister."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Voorsien \'n vertroude agent."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Laat \'n program toe om \'n vertroude agent te voorsien."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Verbind met \'n vertrouensagentdiens"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Laat \'n program toe om met \'n vertrouensagentdiens te verbind."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Tree in wisselwerking met opdatering- en terugstellingstelsel"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 0d315a2..da89136 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android ስርዓት"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"የግል"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"ስራ"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"የግል መተግበሪያዎች"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android ስራ"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"ገንዘብ የሚያስወጥዎ አገልግሎቶች"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ገንዘብ የሚያስወጡህን ነገሮች አድርግ።"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"መልዕክቶችዎ"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ልጣፍ ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"ከአንድ የድምጽ በይነተገናኝ ጋር ይሰሩ"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"ያዢው የአንድ የድምጽ በይነግንኙነት አገልግሎት የከፍተኛ ደረጃ በይነገጽ እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"ድምጽ የቁልፍ ሃረጎችን አስተዳድር"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"መያዣው የቁልፍ ሃረጎችን ለድምጽ ትኩስ ቃል ለይቶ ማወቂያ እንዲያስተዳድር ይፈቅድለታል። ለመደበኛ መተግበሪያዎች ማስፈለግ የለበትም።"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ከአንድ የርቀት ማሳያ ጋር ይጠርዛል"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ያዢው ከአንድ የርቀት ማሳያ ከፍተኛ-ደረጃ በይነገጽ ጋር እንዲጠርዝ ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ወደ ፍርግም አገልግሎት አያይዝ"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ለመልሰህ አጫውት ፍታን በማንኛውም የተጫኑ በማህደረ መረጃ ዲኮደር ለመጠቀም ለመተግበሪያ ይፈቅዳል።"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"የታመኑ ምስክርነቶችን ያስተዳድሩ"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"መተግበሪያው CA የምስክር ወረቀቶችን እንደሚታመኑ ምስክርነቶች አንዲጭን እና እንዲያራግፍ ይፍቀዱ።"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"ስራ በተፈታበት ጊዜ ላይ መተግበሪያውን አሂድ"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ይህ ፍቃድ መሣሪያው ስራ ላይ ባልሆነ ጊዜ የAndroid ስርዓቱ መተግበሪያውን በጀርባ ውስጥ እንዲያሂደው ያስችለዋል።"</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"መርሐግብር የተያዘለት የመተግበሪያ የጀርባ ስራ አሂድ"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"ይህ ፍቃድ የAndroid ስርዓቱ ሲጠየቅ መተግበሪያውን በጀርባ እንዲያሂደው ይፈቅድለታል።"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"በdiag ባለቤትነት ያሉ ንብረቶችን አንብብ/ፃፍ"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"በዲያግ ቡድን ባለቤትነት ወደ አለ ማንኛውም ንብረት ለምሳሌ በ/dev ያሉ ፋይሎች ለማንበብ እና ለመፃፍ ለመተግበሪያው ይፈቅዳሉ። ይህ በመሰረቱ የስርዓት መረጋጋትን እና ደህንነትን ሊጎዳ ይችላል። ይህ ውስን የሀርድዌር-ተኮር ዲያግኖስቲክስ በአምራቹ ወይም ከዋኙ ብቻ መሆን አለበት።"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"የመተግበሪያ ምንዝሮችን አንቃ ወይም አቦዝን"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"መተግበሪያው የድምጽ ውጽዓት እንዲቀርጽ እና አቅጣጫውን እንዲያዞር ያስችለዋል።"</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ትኩስ ቃል ማወቅ"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"ትኩስ ቃል ለይቶ ለማወቅ ድምጽ እንዲቀርጽ ለመተግበሪያው ይፈቅድለታል። ቀረጻው በጀርባ ሊካሄድ ይችላል ነገር ግን ሌላ የድምጽ ቀረጻዎችን አይከለክልም (ለምሳሌ፣ የካሜራ መቅረጫ)።"</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"የድምጽ ማስተላለፊያ"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"መተግበሪያው በቀጥታ የድምጽ ማስተላለፍን እንዲቆጣጠርና የድምጽ መምሪያ ውሳኔዎችን እንዲጥስ ይፈቅድለታል።"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"የቪዲዮ ውጽዓት ይቅረጹ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"መተግበሪያው የቪዲዮ ውጽዓት እንዲቀርጽ እና አቅጣጫውን እንዲያዞር ያስችለዋል።"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ደህንነቱ የተጠበቀ የቪዲዮ ውጽዓት ይቅረጹ"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"አንድ መተግበሪያ የቁልፍ መጠበቂያውን እንዲቆጣጠር ያስችለዋል።"</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"የተአማኒነት ሁኔታ ለውጦችን አዳምጥ።"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"መተግበሪያው በተአማኒነት ሁኔታ ውስጥ ለውጦችን እንዲያዳምጥ ይፈቅዳል።"</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"የመታመን ወኪል ያቅርቡ።"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"አንድ መተግበሪያ የመታመን ወኪል እንዲያቀርብ ይፈቅድለታል።"</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"የእምነት ወኪል ቅንብሮች ምናሌን አስጀምር።"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"አንድ መተግበሪያ የእምነት ወኪል ባህሪ የሚቀይር እንቅስቃሴ እንዲያስጀምር ያስችለዋል።"</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ለተአማኒነት ወኪል አገልግሎት ተገዢ አድርግ"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"ለመተግበሪያን የተአማኒነት ወኪል አገልግሎትን እንዲያከብር ይፈቅዳል።"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"ከዝማኔዎች እና ከመልሶ ማግኛ ስርዓቶች ጋር ይገናኙ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index fbdaab4..626858f 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
<string name="android_system_label" msgid="6577375335728551336">"نظام Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"شخصي"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"عمل"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"التطبيقات الشخصية"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"عمل Android"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"الخدمات التي تكلفك المال"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"يمكنك تنفيذ إجراءات يمكن أن تكلفك مالاً."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"رسائلك"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للخلفية. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"الربط بخدمة التفاعل الصوتي"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"للسماح للمالك بالربط بواجهة المستوى العلوي لخدمة التفاعل الصوتي. لن تكون هناك حاجة إلى هذا الإعداد مطلقًا مع التطبيقات العادية."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"إدارة العبارات الأساسية الصوتية"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"للسماح للمالك بإدارة العبارات الأساسية لاكتشاف الكلمات المهمة الصوتية. لا يجب استخدامه على الإطلاق للتطبيقات العادية."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"الربط بالشاشة عن بُعد"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للعرض عن بُعد. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"الالتزام بخدمة أداة"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"السماح للتطبيق باستخدام أي برنامج فك تشفير وسائط مثبت لفك التشفير من أجل التشغيل."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"إدارة بيانات الاعتماد الموثوقة"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"السماح للتطبيق بتثبيت شهادات CA وإلغاء تثبيتها باعتبارها بيانات اعتماد محل ثقة."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"تشغيل التطبيق أثناء وقت الخمول"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"يتيح هذا الإذن لنظام Android تشغيل التطبيق في الخلفية في حين أن الجهاز ليس قيد الاستخدام."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"تشغيل عمل الخلفية المجدول للتطبيق"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"يتيح هذا الإذن لنظام Android تشغيل التطبيق في الخلفية عند طلبه."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"قراءة/كتابة إلى الموارد المملوكة بواسطة التشخيص"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"للسماح للتطبيق بالقراءة والكتابة إلى أي مورد مملوك بواسطة مجموعة التشخيصات؛ على سبيل المثال، الملفات في /dev. من المحتمل أن يؤثر ذلك في استقرار النظام وأمانه. يجب ألا يستخدم ذلك سوى للتشخيصات الخاصة بالنظام من قِبل المصنِّع أو المشغِّل."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"تمكين مكونات التطبيق أو تعطيلها"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"السماح للتطبيق بالتقاط إخراج الصوت وإعادة توجيهه."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"اكتشاف الكلمة المهمة"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"للسماح للتطبيق بالتقاط الصوت لاكتشاف الكلمة المهمة. يمكن أن يتم الالتقاط في الخلفية ولكنه لا يمنع التقاط الأصوات الأخرى (على سبيل المثال، كاميرا الفيديو)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"التوجيه الصوتي"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"للسماح للتطبيق بالتحكم المباشر في التوجيه الصوتي وتجاوز قرارات السياسات الصوتية."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"التقاط إخراج الفيديو"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"السماح للتطبيق بالتقاط إخراج الفيديو وإعادة توجيهه."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"التقاط إخراج الفيديو الآمن"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"للسماح لأحد التطبيقات بالتحكم في قفل المفاتيح."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"معرفة تغييرات حالة الاعتماد."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"للسماح للتطبيق بالتعرف على التغييرات في حالة الاعتماد."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"توفير وكيل معتمد."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"للسماح لأحد التطبيقات بتوفير وكيل معتمد."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"تشغيل قائمة إعدادات الوكيل المعتمد."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"للسماح لأحد التطبيقات بتشغيل نشاط يؤدي إلى تغيير سلوك الوكيل المعتمد."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"الالتزام بخدمة الوكيل المعتمد"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"للسماح لأحد التطبيقات بالالتزام بخدمة الوكيل المعتمد."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"التفاعل مع نظام التحديث والاسترداد"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 59bb807..ca71ce3 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Системно от Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Личен"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Служебен"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Лични приложения"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Служебен под Android"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Услуги, които ви струват пари"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Извършват неща, които могат да ви струват пари."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Вашите съобщения"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на тапет. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"свързване с услуга за гласово взаимодействие"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Разрешава на притежателя да се свърже с интерфейса от най-високото ниво на услуга за гласово взаимодействие. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"управление на гласовите ключови фрази"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Разрешава на притежателя да управлява ключовите фрази за функцията за откриване на произнесени активиращи думи. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"свързване с отдалечен екран"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Разрешава на притежателя да се свърже с интерфейса от първо ниво на отдалечен екран. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обвързване с услуга за приспособления"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Разрешава на приложението да използва всеки инсталиран медиен декодер с цел декодиране за възпроизвеждане."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"управление на надеждните идентификационни данни"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Разрешава на приложението да инсталира и деинсталира сертификати от сертифициращи органи като надеждни идентификационни данни."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"изпълняване на приложението по време на неактивност"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Това разрешение позволява на системата Android да изпълнява приложението на заден план, докато устройството не се използва."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"изпълняване на планираната за извършване на заден план работа на приложението"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Това разрешение позволява на системата Android да изпълнява приложението на заден план при заявяване."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"четене/запис в ресурси, притежавани от diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Разрешава на приложението да чете и записва във всеки ресурс, притежаван от групата diag, например файловете в /dev. Това потенциално може да засегне стабилността и сигурността на системата. То трябва да се използва САМО за диагностика, конкретно за хардуера, от страна на производителя или оператора."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"активиране или деактивиране на компоненти на приложенията"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Разрешава на приложението да записва и пренасочва възпроизвеждания звук."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Откриване на активиращи думи"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Разрешава на приложението да записва звук с цел откриване на активиращи думи. Това може да става на заден план, но не пречи на записването на други звуци (напр. от видеокамерата)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Аудиомаршрутизиране"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Разрешава на приложението директно да контролира аудиомаршрутизирането и да заменя решенията на аудиоправилата."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"записване на възпроизвеждания образ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Разрешава на приложението да записва и пренасочва възпроизвеждания образ."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"записване на защитеното възпроизвеждане на образ"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Разрешава на приложението да контролира функцията за защита на клавишите."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Следене за промени в състоянието на надеждност"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Разрешава на приложението да следи за промени в състоянието на надеждност."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Предоставяне на trust agent."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Разрешава на приложението да предоставя trust agent."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Обвързване с услуга за trust agents"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Разрешава на приложението да се обвърже с услуга за trust agents."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Взаимодействие със системата за актуализации и възстановяване"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index a53c131..e1eed49 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"+999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Feina"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Aplicacions personals"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Lloc a Android"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Serveis de pagament"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Dur a terme activitats de pagament."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Missatges"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet que el titular vinculi a la interfície de nivell superior d\'un fons de pantalla. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"enllaçar amb una eina d\'interacció de veu"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permet enllaçar amb la interfície de nivell superior d\'un servei d\'interacció de veu. No ha de ser mai necessari per a aplicacions normals."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gestiona les frases clau en veu alta"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permet que l\'usuari gestioni les frases clau per detectar paraules actives que es diguin en veu alta. Mai no hauria de ser necessari per a les aplicacions habituals."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vincula a una pantalla remota"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permet que el titular es vinculi a la interfície de nivell superior d\'una pantalla remota. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincula a un servei de widget"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet que l\'aplicació utilitzi qualsevol descodificador de mitjans instal·lat per descodificar per a la reproducció."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestiona les credencials de confiança"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet que l\'aplicació instal·li i desinstal·li certificats de CA com a credencials de confiança."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"executar l\'aplicació durant el temps d\'inactivitat"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Aquest permís permet que el sistema Android executi l\'aplicació en segon pla mentre el dispositiu no està en ús."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"executa les tasques programades de l\'aplicació en segon pla"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Mitjançant aquest permís, el sistema Android pot executar l\'aplicació en segon pla quan se li ho sol·liciti."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"llegir/escriure recursos propietat de diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet que l\'aplicació llegeixi i escrigui a qualsevol recurs propietat del grup diag; per exemple, els fitxers de /dev. Això podria afectar l\'estabilitat i la seguretat del sistema. NOMÉS l\'hauria d\'utilitzar el fabricant o l\'operador per a diagnòstics específics de maquinari."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activa o desactiva els components de l\'aplicació"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permet que l\'aplicació capturi i redirigeixi la sortida d\'àudio."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detecció de paraules actives"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permet que l\'aplicació capturi àudio per a la detecció de paraules actives. La captura es pot produir en segon pla però no evita altres captures d\'àudio (per exemple, de càmera de vídeo)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Encaminament d\'àudio"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Permet que l\'aplicació controli directament l\'encaminament d\'àudio i sobreescrigui les decisions relacionades amb la política d\'àudio."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"captura la sortida de vídeo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permet que l\'aplicació capturi i redirigeixi la sortida de vídeo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"captura la sortida de vídeo segur"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permet que una aplicació controli el bloqueig de les tecles."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Escoltar els canvis de l\'estat de confiança"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permet que una aplicació escolti els canvis en l\'estat de confiança."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Proporcionar un agent de confiança"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permet que una aplicació proporcioni un agent de confiança."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Enllaçar amb el servei d\'un agent de confiança"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permet que una aplicació es vinculi amb el servei d\'un agent de confiança."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interacciona amb el sistema de recuperació i amb les actualitzacions"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index a1e99fa..cf06dc1 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Osobní"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Práce"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Osobní aplikace"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android pro práci"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Zpoplatněné služby"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Provádět činnosti, které vás mohou stát peníze."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vaše zprávy"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní tapety. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"navázání na hlasovou interakci"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní služby hlasové interakce. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"správa klíčových hlasových frází"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Umožňuje držiteli spravovat klíčové hlasové fráze pro detekci hlasových klíčových slov. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"připojit se ke vzdálenému displeji"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Umožňuje držiteli připojit se k vysokoúrovňovému rozhraní vzdáleného displeje. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"navázat se na službu widgetu"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Umožňuje aplikaci používat libovolný nainstalovaný dekodér médií k dekódování při přehrávání."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"správa důvěryhodných identifikačních údajů"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Umožňuje aplikaci instalovat a odinstalovat certifikáty CA jako důvěryhodné identifikační údaje."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"spustit aplikaci během nečinnosti"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Toto oprávnění umožňuje systému Android spustit aplikaci na pozadí, když zařízení není používáno."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"spustit naplánovanou práci aplikace na pozadí"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Toto oprávnění umožňuje systému Android spustit aplikaci na pozadí, když je to požadováno."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"čtení nebo zápis do prostředků funkce diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Umožňuje aplikaci číst libovolné prostředky ve skupině diag, např. soubory ve složce /dev, a zapisovat do nich. Může dojít k ovlivnění stability a bezpečnosti systému. Toto nastavení by měl používat POUZE výrobce či operátor pro diagnostiku hardwaru."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivace či deaktivace komponent aplikací"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Umožní aplikaci zachytit a přesměrovat výstup zvuku."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detekce klíčových slov"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Umožní aplikaci zachytávat zvuk za účelem detekce klíčových slov. Zachytávání může probíhat na pozadí a nebrání jinému zaznamenávání zvuku (například videokamerou)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Směrování zvuku"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Umožňuje aplikaci převzít přímou kontrolu nad směrováním zvuku a přepsat nastavené zásady zvuku."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"zachytit výstup videa"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Umožní aplikaci zachytit a přesměrovat výstup videa."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"zachytit zabezpečený výstup videa"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Umožňuje aplikaci ovládat zámek obrazovky."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Naslouchat změnám stavu důvěryhodnosti"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Umožňuje aplikaci naslouchat změnám ve stavu důvěryhodnosti."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Poskytování zástupce důvěryhodnosti"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Umožňuje aplikaci poskytnout zástupce důvěryhodnosti."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vázat se na službu zástupce důvěryhodnosti"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Umožňuje aplikaci vázat se na službu zástupce důvěryhodnosti."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interakce se systémem aktualizací a obnovení"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index b17b8c6..0aa2a36 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personlig"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Arbejde"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Personlige apps"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Tjenester, der koster dig penge"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Gør ting, der kan koste dig penge."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Dine beskeder"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Tillader, at indehaveren kan binde en baggrunds grænseflade på øverste niveau. Dette bør aldrig være nødvendigt for almindelige apps."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"oprette binding til en tjeneste til stemmeinteraktion"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Tillader, at brugeren opretter en binding til det øverste niveau af grænsefladen i en tjeneste til stemmeinteraktion. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"administrer nøglesætninger til stemmeregistrering"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Tillader, at brugeren kan administrere nøglesætningerne til stemmeregistrering af kommandoord. Dette bør aldrig være nødvendigt for almindelige apps."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind til en ekstern skærm"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Tillader, at brugeren kan foretage en binding til grænsefladens øverste niveau på en ekstern skærm. Bør aldrig være nødvendigt til almindelige apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"forpligt til en widgettjeneste"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Tillader, at appen bruger enhver installeret medieafkoder til at afkode til afspilning."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrer pålidelige logonoplysninger"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Tillader, at appen installerer og afinstallerer CA-certifikater som pålidelige loginoplysninger."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"kør applikation, mens enheden er i dvale"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Med denne tilladelse kan Android-systemet køre applikationen i baggrunden, mens enheden ikke er i brug."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"kør applikationens planlagte baggrundsarbejde"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Med denne tilladelse kan Android-systemet køre applikationen i baggrunden, når det er nødvendigt."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"læs/skriv til ressourcer ejet af diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Tillader, at appen kan læse og skrive til alle ressourcer, der ejes af diag-gruppen, f.eks. filer i /dev. Dette kan muligvis påvirke systemets stabilitet og sikkerhed. Dette bør KUN bruges til hardwarespecifik diagnosticering, som foretages af producenten eller udbyderen."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivere eller deaktivere appkomponenter"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Tillader, at appen opfanger og omdirigerer et lydoutput."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Registrering af kommandoord"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Tillader, at appen optager lyd til registrering af kommandoord. Optagelsen kan ske i baggrunden, men forhindrer ikke andre lydoptagelser (f.eks. videokamera)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Lydhåndtering"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Tillader, at appen direkte kontrollerer lydhåndteringen og tilsidesætter beslutninger, baseret på af lydpolitikker."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"opfang et videooutput"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Tillader, at appen opfanger og omdirigerer et videooutput."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"opfang et sikkert videooutput"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Tillader, at en applikation styrer nøglebeskyttelsen."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Registrere ændringer i trust-tilstand."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Tillader, at en applikation registrerer ændringer i trust-tilstand."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Angiv en tillidsagent."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Tillader, at en applikation angiver en tillidsagent."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Åbn indstillingsmenuen for tillidsagenten"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Giver en applikation tilladelse til at starte en aktivitet, som ændrer adfærden for tillidsagenten."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Knytte sig til en trust agent-tjeneste"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Tillader, at en applikation knytter sig til en trust agent-tjeneste."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interager med opdaterings- og gendannelsessystemet"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 70c12cd..d557d37 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Privat"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Geschäftlich"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Private Apps"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android – Arbeit"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Kostenpflichtige Dienste"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Kostenpflichtige Aktionen"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Ihre Nachrichten"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ermöglicht dem Halter, sich an die Oberfläche eines Hintergrunds auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"An einen Sprachinteraktionsdienst binden"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Sprachinteraktionsdienstes auf oberster Ebene zu binden. Für normale Apps sollte dies nie erforderlich sein."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"Suchbegriffe für die Sprachsuche verwalten"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Ermöglicht dem Inhaber die Verwaltung von Suchbegriffen für die Hotword-Erkennung bei der Sprachbedienung. Für normale Apps sollte dies nie erforderlich sein."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"An Remote-Display binden"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ermöglicht dem Halter, sich an die Oberfläche eines Remote-Displays auf oberster Ebene zu binden. Sollte für normale Apps nie benötigt werden."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"An einen Widget-Dienst binden"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ermöglicht der App, alle installierten Mediendecodierer zur Wiedergabe zu verwenden."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Vertrauenswürdige Anmeldedaten verwalten"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ermöglicht der App, CA-Zertifikate als vertrauenswürdige Anmeldedaten zu installieren und zu deinstallieren."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"App bei Inaktivität ausführen"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Diese Berechtigung ermöglicht es dem Android-System, die App im Hintergrund auszuführen, wenn das Gerät nicht verwendet wird."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"Geplante Aufgaben der App im Hintergrund ausführen"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Diese Berechtigung ermöglicht es dem Android-System, die App bei Bedarf im Hintergrund auszuführen."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Ermöglicht der App, alle Elemente in der Diagnosegruppe zu lesen und zu bearbeiten, etwa Dateien in \"/dev\". Dies könnte eine potenzielle Gefährdung für die Stabilität und Sicherheit des Systems darstellen und sollte NUR für hardwarespezifische Diagnosen des Herstellers oder Mobilfunkanbieters verwendet werden."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"App-Komponenten aktivieren oder deaktivieren"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Ermöglicht der App die Erfassung und Weiterleitung von Audioausgaben"</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword-Erkennung"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"App darf Audio für die Hotword-Erkennung erfassen. Dies kann im Hintergrund durchgeführt werden und beeinflusst die Erfassung von Audio über andere Funktionen (z. B. Camcorder) nicht."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Audiorouting"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Ermöglicht der App die direkte Steuerung des Audiorouting und das Außerkraftsetzen von Entscheidungen der Audiorichtlinien"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"Videoausgabe erfassen"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Ermöglicht der App die Erfassung und Weiterleitung von Videoausgaben"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"Sichere Videoausgabe erfassen"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Apps können den Keyguard steuern."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Überwachung von Änderungen des Trust-Status"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Ermöglicht einer App die Überwachungen von Änderungen des Trust-Status"</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Trust Agent bereitstellen"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Ermöglich die Bereitstellung eines Trust Agents durch eine App"</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Einstellungsmenü des Trust Agents starten"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Ermöglicht einer App das Starten einer Aktivität, die das Verhalten des Trust Agents ändert"</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"An Trust Agent-Service anbinden"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ermöglicht einer App die Anbindung an einen Trust Agent-Service"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Mit Update- und Wiederherstellungssystem interagieren"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index d0561b9..8205c60 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
<string name="android_system_label" msgid="6577375335728551336">"Σύστημα Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Προσωπικό"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Εργασία"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Προσωπικές εφαρμογές"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Υπηρεσίες επί πληρωμή"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Πραγματοποίηση ενεργειών για τις οποίες ενδέχεται να χρεωθείτε."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Τα μηνύματά σας"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας ταπετσαρίας. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"σύνδεση σε παράγοντα φωνητικής αλληλεπίδρασης"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Επιτρέπει στον κάτοχο τη σύνδεση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας φωνητικής αλληλεπίδρασης. Δεν απαιτείται για κανονικές εφαρμογές."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"διαχείριση φωνητικών φράσεων-κλειδιών"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Δίνει στον κάτοχο τη δυνατότητα να διαχειριστεί τις φράσεις-κλειδιά για την ανίχνευση φωνητικών λέξεων-κλειδιών. Δεν απαιτείται για τις συνήθεις εφαρμογές."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"μεταφορά σε μια απομακρυσμένη οθόνη"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας απομακρυσμένης οθόνης. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"δέσμευση σε υπηρεσία γραφικών στοιχείων"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Επιτρέπει στην εφαρμογή τη χρήση οποιουδήποτε εγκατεστημένου αποκωδικοποιητή μέσων για αναπαραγωγή."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"διαχείριση αξιόπιστων διαπιστευτηρίων"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Επιτρέπει στην εφαρμογή την εγκατάσταση και την απεγκατάσταση πιστοποιητικών CA ως αξιόπιστων διαπιστευτηρίων."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"εκτέλεση εφαρμογής κατά τη λειτουργία αδράνειας"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Αυτή η άδεια επιτρέπει στο σύστημα Android να εκτελεί την εφαρμογή στο παρασκήνιο όταν δεν χρησιμοποιείται η συσκευή."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"εκτέλεση των προγραμματισμένων εργασιών της εφαρμογής στο παρασκήνιο"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Αυτή η άδεια επιτρέπει στο σύστημα Android να εκτελεί την εφαρμογή στο παρασκήνιο όταν ζητηθεί."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ανάγνωση/εγγραφή σε πόρους που ανήκουν στο διαγνωστικό"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Επιτρέπει στην εφαρμογή την ανάγνωση και την εγγραφή σε οποιονδήποτε πόρο που ανήκει στην ομάδα διαγνωστικού (π.χ. αρχεία στον κατάλογο /dev). Αυτό ενδέχεται να επηρεάσει την σταθερότητα και την ασφάλεια του συστήματος. Θα πρέπει να χρησιμοποιείται ΜΟΝΟ για διαγνωστικά υλικού από τον κατασκευαστή ή τον χειριστή."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ενεργοποίηση ή απενεργοποίηση στοιχείων εφαρμογής"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Δίνει στην εφαρμογή τη δυνατότητα εγγραφής και ανακατεύθυνσης εξόδου ήχου."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Ανίχνευση ενεργών λέξεων"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Επιτρέπει στην εφαρμογή την εγγραφή ήχου για ανίχνευση ενεργών λέξεων. Η εγγραφή μπορεί να πραγματοποιηθεί στο παρασκήνιο, αλλά δεν εμποδίζει την εγγραφή ήχου από άλλες πηγές (π.χ. βιντεοκάμερα)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Δρομολόγηση ήχου"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Επιτρέπει στην εφαρμογή να ελέγχει άμεσα τη δρομολόγηση ήχου και αντικαθιστά τις αποφάσεις πολιτικής ήχου."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"έγγραφή εξόδου βίντεο"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Δίνει στην εφαρμογή τη δυνατότητα εγγραφής και ανακατεύθυνσης εξόδου βίντεο."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"έγγραφή ασφαλούς εξόδου βίντεο"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Επιτρέπει σε μια εφαρμογή τον έλεγχο του κλειδώματος πληκτρολογίου."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Αντίληψη αλλαγών καταστάσεων εμπιστοσύνης."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Επιτρέπει σε μια εφαρμογή να αντιλαμβάνεται τις αλλαγές στην κατάσταση εμπιστοσύνης."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Παράσχετε έναν αξιόπιστο αντιπρόσωπο."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Επιτρέπει σε μια εφαρμογή να προσφέρει έναν αξιόπιστο αντιπρόσωπο."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Εκκίνηση μενού ρυθμίσεων αξιόπιστου αντιπροσώπου."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Επιτρέπει σε μια εφαρμογή να εκκινεί μια ενέργεια που αλλάζει τη συμπεριφορά του αξιόπιστου αντιπροσώπου."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Σύνδεση σε υπηρεσία trust agent"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Επιτρέπει σε μια εφαρμογή να συνδεθεί σε μια υπηρεσία trust agents."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Αλληλεπίδραση με το σύστημα ενημέρωσης και ανάκτησης"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 1237f38..a0c35c8 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Work"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Personal apps"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services that cost you money"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Do things that can cost you money."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Your messages"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for normal applications."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bind to a voice interactor"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Allows the holder to bind to the top-level interface of a voice interaction service. Should never be needed for normal apps."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"manage voice key phrases"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Allows the holder to manage the key phrases for voice hotword detection. Should never be needed for normal apps."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind to a remote display"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Allows the holder to bind to the top-level interface of a remote display. Should never be needed for normal apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind to a widget service"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Allows the app to use any installed media decoder to decode for playback."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"manage trusted credentials"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Allows the app to install and uninstall CA certificates as trusted credentials."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"run application during idle time"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"This permission allows the Android system to run the application in the background while the device is not in use."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"run the application\'s scheduled background work"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"This permission allows the Android system to run the application in the background when requested."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"read/write to resources owned by diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Allows the app to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"enable or disable app components"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Allows the app to capture and redirect audio output."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword detection"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Allows the app to capture audio for Hotword detection. The capture can happen in the background but does not prevent other audio capture (e.g. Camcorder)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Audio Routing"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Allows the app to directly control audio routing and override audio policy decisions."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capture video output"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Allows the app to capture and redirect video output."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capture secure video output"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Allows an application to control keyguard."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Listen to trust state changes."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Allows an application to listen for changes in trust state."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Provide a trust agent."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Allows an application to provide a trust agent."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Lunch trust agent settings menu."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Allows an application to lunch an activity that changes the trust agent behaviour."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind to a trust agent service"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Allows an application to bind to a trust agent service."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interact with update and recovery system"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 1237f38..a0c35c8 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Work"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Personal apps"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services that cost you money"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Do things that can cost you money."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Your messages"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for normal applications."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bind to a voice interactor"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Allows the holder to bind to the top-level interface of a voice interaction service. Should never be needed for normal apps."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"manage voice key phrases"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Allows the holder to manage the key phrases for voice hotword detection. Should never be needed for normal apps."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind to a remote display"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Allows the holder to bind to the top-level interface of a remote display. Should never be needed for normal apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind to a widget service"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Allows the app to use any installed media decoder to decode for playback."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"manage trusted credentials"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Allows the app to install and uninstall CA certificates as trusted credentials."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"run application during idle time"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"This permission allows the Android system to run the application in the background while the device is not in use."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"run the application\'s scheduled background work"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"This permission allows the Android system to run the application in the background when requested."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"read/write to resources owned by diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Allows the app to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"enable or disable app components"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Allows the app to capture and redirect audio output."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotword detection"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Allows the app to capture audio for Hotword detection. The capture can happen in the background but does not prevent other audio capture (e.g. Camcorder)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Audio Routing"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Allows the app to directly control audio routing and override audio policy decisions."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capture video output"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Allows the app to capture and redirect video output."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capture secure video output"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Allows an application to control keyguard."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Listen to trust state changes."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Allows an application to listen for changes in trust state."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Provide a trust agent."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Allows an application to provide a trust agent."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Lunch trust agent settings menu."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Allows an application to lunch an activity that changes the trust agent behaviour."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind to a trust agent service"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Allows an application to bind to a trust agent service."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interact with update and recovery system"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 0f272c4..b6a7667 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Trabajo"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Aplicaciones personales"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Trabajo Android"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servicios que te cuestan dinero"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Permite que las aplicaciones realicen actividades con cargo."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Tus mensajes"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite al propietario vincularse a la interfaz de nivel superior de un fondo de pantalla. Las aplicaciones normales no deben utilizar este permiso."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"vincular con un servicio de interacción por voz"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite vincular con la interfaz de nivel superior de un servicio de interacción por voz. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"administrar frases clave de voz"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permite administrar las frases clave para detección de palabras activas de voz. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vincular a una pantalla remota"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite al propietario vincularse a la interfaz de nivel superior de una pantalla remota. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a un servicio de widget"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrar credenciales de confianza"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que la aplicación instale y desinstale certificados de CA como credenciales de confianza."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"ejecutar la aplicación durante el tiempo de inactividad"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Con este permiso, el sistema Android puede ejecutar la aplicación en segundo plano mientras el dispositivo no está en uso."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"Ejecutar el trabajo en segundo plano programado de la aplicación"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Con este permiso, el sistema Android puede ejecutar la aplicación en segundo plano cuando sea necesario."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar la seguridad y estabilidad del sistema. SOLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activar o desactivar componentes de la aplicación"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite que la aplicación capture y redirija la salida de audio."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detectar palabras activas"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permite que la aplicación capture audio para la detección de palabras activas. La captura puede realizarse en segundo plano, pero no impide otras capturas de audio (por ejemplo, de la videocámara)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Enrutamiento de audio"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Permite que la aplicación controle directamente el enrutamiento de audio y anule las decisiones de políticas de audio."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"Capturar salida de video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite que la aplicación capture y redirija la salida de video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"Capturar salida de video segura"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que una aplicación controle los bloqueos."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Detectar cambios en estado de confianza"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que una aplicación detecte cambios en el estado de confianza."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Proporcionar un agente de confianza"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite que una aplicación proporcione un agente de confianza."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Iniciar menú de configuración de agente de confianza"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Permite que una aplicación inicie una actividad que modifica el comportamiento del agente de confianza."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vincular con un servicio de agente de confianza"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que una aplicación se vincule con un servicio de agente de confianza."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interaccionar con el sistema de recuperación y las actualizaciones"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index cfc8b61..1dcbf62 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"> 999"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Trabajo"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Aplicaciones personales"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Trabajo Android"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servicios por los que tienes que pagar"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Hacer acciones por las que puede que tengas que pagar"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Tus mensajes"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite enlazar con la interfaz de nivel superior de un fondo de pantalla. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"enlazar con un servicio de interacción de voz"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite enlazar con la interfaz de nivel superior de un servicio de interacción de voz. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"administrar frases clave de voz"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permite administrar las frases clave para la detección de palabras activas. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"enlazar a una pantalla remota"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite enlazar con la interfaz de nivel superior de una pantalla remota. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"enlazar con un servicio de widget"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrar credenciales de confianza"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que la aplicación instale y desinstale certificados de CA como credenciales de confianza."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"ejecutar la aplicación durante el tiempo de inactividad"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Esto permite que el sistema Android ejecute la aplicación en segundo plano mientras el dispositivo no se utiliza."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"ejecutar el trabajo en segundo plano programado de la aplicación"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Esto permite que el sistema Android ejecute la aplicación en segundo plano cuando se solicite."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"leer/escribir en los recursos propiedad del grupo de diagnóstico"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación consulte y escriba en cualquier recurso del grupo de diagnóstico como, por ejemplo, archivos en /dev. Este permiso podría afectar a la seguridad y estabilidad del sistema. SOLO se debe usar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"habilitar o inhabilitar componentes de la aplicación"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite que la aplicación capture y redirija la salida de audio."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detectar palabras activas"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permite que la aplicación grabe audio para detectar palabras activas. La grabación se puede realizar en segundo plano pero no impide que se grabe otro tipo de audio (p.ej. la videocámara)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Enrutamiento de audio"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Permite que la aplicación controle directamente el enrutamiento de audio y anule las decisiones de políticas de audio."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capturar salida de vídeo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite que la aplicación capture y redirija la salida de vídeo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capturar salida de vídeo segura"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que una aplicación controle los bloqueos."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Detectar cambios en el estado de confianza."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que una aplicación detecte cambios en el estado de confianza."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Proporcionar un agente de confianza."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite que una aplicación proporcione un agente de confianza."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Abre el menú de ajustes del agente de confianza."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Permite que una aplicación inicie una actividad que cambie el comportamiento del agente de confianza."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Enlazar con un servicio de agente de confianza"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite a una aplicación enlazar con un servicio de agente de confianza."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interactuar con el sistema de recuperación y las actualizaciones"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 8c2112a..60d036e 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Isiklik"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Töö"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Isiklikud rakendused"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android tööl"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Tasulised teenused"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Tasuliste toimingute tegemine."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Teie sõnumid"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lubab omanikul siduda taustapildi ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"seo häälinteraktsiooniga"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Lubab omanikul siduda häälinteraktsiooni teenuse ülataseme liidesega. Pole kunagi vajalik tavaliste rakenduste puhul."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"häältuvastuse võtmefraaside haldus"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Võimaldab omanikul hallata häältuvastuse otsetee sõna võtmefraase. Seda ei tohiks tavaliste rakenduste puhul kunagi vaja olla."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"kaugekraaniga sidumine"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lubab omanikul siduda rakenduse kaugekraani ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vidinateenusega sidumine"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Võimaldab rakendusel taasesituseks kasutada mis tahes installitud meediumidekooderit."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"usaldusväärsete mandaatide haldamine"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lubab rakendusel installida ja desinstallida usaldusväärsete mandaatidena CA-sertifikaate."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"rakenduse käitamine tegevusetul ajal"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"See luba võimaldab Android-süsteemil käitada rakendust taustal siis, kui seadet ei kasutata."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"rakenduse ajastatud taustatoimingu käitamine"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"See luba võimaldab Android-süsteemil rakendust soovi korral taustal käitada."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"loe/kirjuta valija allikaid"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Võimaldab rakendusel lugeda valimisrühma mis tahes ressurssi ja sellesse kirjutada (näiteks kaustas /dev olevad failid). See võib mõjutada süsteemi stabiilsust ja turvet. Seda tohiks kasutada tootja või operaator AINULT riistvaraspetsiifiliseks diagnostikaks."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"Rakenduse komponentide lubamine või keelamine"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Lubab rakendusel jäädvustada ja ümber suunata heliväljundit."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Otsetee sõna tuvastamine"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Lubab rakendusel jäädvustada heli otsetee sõna tuvastamiseks. Jäädvustamine võib toimuda taustal, kuid see ei takista muud heli jäädvustamist (nt videokaameraga)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Heli marsruutimine"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Võimaldab rakendusel otse juhtida heli marsruutimist ja alistada helieeskirjade otsused."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"videoväljundi jäädvustamine"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Lubab rakendusel jäädvustada ja ümber suunata videoväljundit."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"kaitstud videoväljundi jäädvustamine"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Lubab rakendusel võtmekaitset juhtida."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Usaldusväärse oleku muudatuste tuvastamine."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Lubab rakendusel tuvastada muudatusi usaldusväärses olekus."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Usaldusväärse agendi esitamine."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Võimaldab rakendusel esitada usaldusväärset agenti."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Käivita usaldusväärse agendi seadete menüü."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Võimaldab rakendusel käivitada tegevuse, mis muudab usaldusväärse agendi käitumist."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Usaldusväärse agendi teenusega sidumine"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Lubab rakendusel ennast siduda usaldusväärse agendi teenusega."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Suhtlemine värskenduse ja taastesüsteemiga"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 2a03ca8..b4727bb 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"بیشتر از 999"</string>
<string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
<string name="android_system_label" msgid="6577375335728551336">"سیستم Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"شخصی"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"محل کار"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"برنامههای شخصی"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"سرویسهای غیر رایگان"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"انجام کارهایی که برای شما هزینه دارد."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"پیامهای شما"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"به دارنده اجازه میدهد تا به رابط سطح بالای تصویر زمینه متصل شود. برنامههای معمولی هرگز به این ویژگی نیاز ندارند."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"مقید بودن به سرویس تعامل صوتی"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"به دارنده امکان میدهد به واسط سطح بالای سرویس تعامل صوتی مقید باشد. برای برنامههای عادی هرگز نباید لازم باشد."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"مدیریت عبارات کلیدی صوتی"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"به دارنده امکان میدهد عبارات کلیدی برای شناسایی کلیدگفته صوتی را مدیریت کند. هرگز نباید برای برنامههای معمولی مورد نیاز باشد."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"اتصال به نمایشگر راه دور"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"به دارنده امکان میدهد تا به رابط سطح بالای نمایشگر راه دور وصل شود. نباید هرگز برای برنامههای عادی لازم باشد."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"اتصال به یک سرویس ابزارک"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"اجازه میدهد برنامه از هر رمزگشای رسانه نصب شدهای استفاده کند تا برای پخش رمزگشایی شود."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"مدیریت اطلاعات کاربری مورد اعتماد"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"به برنامه امکان میدهد گواهینامههای CA را به عنوان اطلاعات کاربری مورد اعتماد نصب یا حذف نصب کند."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"اجرای برنامه در هنگام بدون فعالیت بودن دستگاه"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"این مجوز به سیستم Android امکان میدهد تا وقتی دستگاه استفاده نمیشود برنامه را در پسزمینه اجرا کند."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"اجرای کار پسزمینه زمانبندی شده برای برنامه"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"این مجوز، به سیستم Android امکان میدهد در صورت تقاضا، برنامه را در پسزمینه اجرا کند."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"خواندن/نوشتن منابع متعلق به تشخیص"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"به برنامه اجازه میدهد هر منبعی را که متعلق به گروه تشخیص است بخواند و در آن بنویسد؛ بهعنوان مثال، فایلهای /dev. این امر بهصورت بالقوه میتواند بر پایدار بودن و امنیت سیستم تأثیر بگذارد. این تنها باید برای تشخیصهای مختص سختافزار توسط تولیدکننده یا اپراتور استفاده شود."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"فعال یا غیر فعال کردن اجزای برنامه"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"به برنامه امکان میدهد خروجی صدا را ضبط و هدایت کند."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"تشخیص کلیدگفته"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"به برنامه اجازه میدهد تا صدا را برای تشخیص کلیدگفته ضبط کند. ضبط صدا میتواند در پسزمینه رخ دهد اما از ضبط صداهای دیگر (مثلاً دوربین فیلمبرداری) جلوگیری نمیکند."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"مسیریابی صوتی"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"به برنامه امکان میدهد تا به طور مستقیم مسیریابی صوتی را کنترل و تصمیمات مربوط به خطمشی صوتی را بازنویسی کند."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"ضبط خروجی ویدیو"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"به برنامه امکان میدهد خروجی ویدیو را ضبط و هدایت کند."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ضبط خروجی ویدیوی ایمن"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"اجازه میدهد برنامهای محافظ کلید را کنترل کند."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"گوش دادن به تغییرات وضعیت trust."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"به یک برنامه کاربردی برای گوش دادن به تغییرات در trust اجازه میدهد."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"یک عامل مورد اعتماد فراهم میآورد."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"به برنامه امکان میدهد یک عامل مورد اعتماد فراهم آورد."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"اتصال به یک سرویس trust agent"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"به یک برنامه کاربردی برای اتصال به یک سرویس trust agent اجازه میدهد."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"تعامل با سیستم بهروزرسانی و بازیابی"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 9398cfa..02c6da4 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -188,8 +188,9 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Henkilökohtainen"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Työ"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Omat sovellukset"</string>
+ <!-- no translation found for managed_profile_label (4287077106125758391) -->
+ <skip />
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Maksulliset palvelut"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Suorita mahdollisesti maksullisia toimintoja."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Omat viestit"</string>
@@ -400,6 +401,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Antaa sovelluksen sitoutua taustakuvan ylätason käyttöliittymään. Ei tavallisten sovellusten käyttöön."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"puheohjauspalveluun sitominen"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Antaa sovelluksen luoda sidoksen puheohjauspalvelun ylätason rajapintaan. Ei tavallisten sovelluksien käyttöön."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"puhuttujen ilmausten hallinta"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Sallii ilmausten hallinnan puhuttujen toimintosanojen tunnistusta varten. Ei tavallisten sovellusten käyttöön."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"etänäyttöön sitoutuminen"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Antaa sovelluksen sitoutua etänäytön ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sitoudu widget-palveluun"</string>
@@ -445,8 +448,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Sallii sovelluksen käyttää mitä tahansa asennettua tietovälineen koodin purkajaa toistoa varten."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"hallinnoi luotettavia varmenteita"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Antaa sovellukselle luvan asentaa ja poistaa luotettavia CA-varmenteita."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"suorita sovellus laitteen ollessa käyttämättömänä"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Tämä oikeus sallii Android-järjestelmän siirtää sovelluksen suorituksen taustalle, kun laite ei ole käytössä."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"suorittaa sovelluksen ajoitetut taustatyöt"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Tämä antaa Android-järjestelmän suorittaa sovelluksen pyydettäessä taustalla."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lue diag:in omistamia resursseja / kirjoita resursseihin"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Antaa sovelluksen lukea ja kirjoittaa diag-ryhmän omistamiin resursseihin, esimerkiksi /dev-hakemistossa oleviin tiedostoihin. Tämä voi vaikuttaa järjestelmän vakauteen ja turvallisuuteen. Tämä lupa tulee myöntää VAIN valmistajan tai operaattorin laitteistotesteille."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"sovelluskomponenttien ottaminen käyttöön tai pois käytöstä"</string>
@@ -520,6 +523,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Antaa sovellukselle luvan äänentoiston kaappaamiseen ja uudelleenohjaamiseen."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Toimintosanan tunnistus"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Antaa sovelluksen siepata ääntä toimintosanojen tunnistusta varten. Sieppaus voi tapahtua taustalla, mutta se ei estä muita laitteita, kuten videokameraa, käyttämästä ääntä."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Äänen reititys"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Antaa sovelluksen hallita äänen reititystä suoraan ja ohittaa ääniä koskevia sääntöjä."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"videokuvan kaappaus"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Antaa sovellukselle luvan videokuvan kaappaamiseen ja uudelleenohjaamiseen"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"suojatun videokuvan kaappaus"</string>
@@ -1356,6 +1361,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Antaa sovelluksen hallita näppäinvahtia."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Seuraa luottamuksen tilamuutoksia."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Antaa sovelluksen seurata luottamuksen tilamuutoksia."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Luotettavan tahon tarjoaminen"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Antaa sovelluksen tarjota luotettavan tahon."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Luotettavaan tahoon sitoutuminen"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Antaa sovelluksen sitoutua luotettavaan tahoon."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Vuorovaikutus päivitys- ja palautusjärjestelmän kanssa"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 9aa2cfe..b1292b3 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personnel"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Travail"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Applications personnelles"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android pour les activités professionnelles"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services payants"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Effectuer des opérations payantes"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vos messages"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un fond d\'écran. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"s\'associer à un service d\'interaction vocale"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'interaction vocale. Ne devrait pas être nécessaire pour les applications standards."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gérer les phrases clés vocales"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permet à l\'utilisateur de gérer les phrases clés pour la détection de mots clés vocaux. Cette option ne devrait jamais être nécessaire pour les applications standards."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"lier à un écran distant"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un écran distant. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"s\'associer à un service de widget"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet à une application d\'utiliser n\'importe quel décodeur installé pour lire les fichiers multimédias."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gérer les certificats de confiance"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet à l\'application d\'installer et de désinstaller les certificats CA en tant que certificats de confiance."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"exécuter l\'application lorsque l\'appareil est inactif"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cette autorisation permet au système Android d\'exécuter l\'application en arrière-plan lorsque l\'appareil est inactif."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"exécuter le travail en arrière-plan planifié de l\'application"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Cette autorisation permet au système Android d\'exécuter l\'application en arrière-plan sur demande."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lire ou modifier les ressources appartenant au groupe de diagnostics"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet à l\'application d\'obtenir des droits en lecture et en écriture pour toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers du répertoire /dev). Cela peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou le fournisseur de services."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activer ou désactiver les composants d\'une application"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Autoriser l\'application à capturer et à rediriger la sortie audio."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Détection de mots clés"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permet à l\'application de capturer de l\'audio pour la détection de mots clés. La capture peut s\'effectuer en arrière-plan, et n\'empêche pas les autres opérations de capture audio (par exemple, avec un caméscope)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Acheminement de l\'audio"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Permet à l\'application de contrôler directement l\'acheminement audio et de remplacer les décisions concernant les politiques audio."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capturer la sortie vidéo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Autoriser l\'application à capturer et à rediriger la sortie vidéo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capturer la sortie vidéo sécurisée"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permet à une application de contrôler la protection des touches."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Détecter les modifications de l\'état de confiance"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permet à une application de détecter les modifications de l\'état de confiance."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Fournir un agent de confiance."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permet à une application de fournir un agent de confiance."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Lier à un service d\'agent de confiance"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permet à une application de se lier à un service d\'agent de confiance."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagir avec le système de récupération et de mise à jour"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 3d043c4..f511df0 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personnel"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Professionnel"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Applications personnelles"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services payants"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Effectuer des opérations payantes"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vos messages"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un fond d\'écran. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"s\'associer à un service d\'interaction vocale"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permet à l\'application de s\'associer à l\'interface de niveau supérieur d\'un service d\'interaction vocale. Ne devrait pas être nécessaire pour les applications standards."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gérer les expressions clés vocales"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permettre à l\'application autorisée de gérer les expressions clés pour la détection de mots clés vocaux. Ne devrait jamais être nécessaire pour les applications standards."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"s\'associer à un écran à distance"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permettre à l\'application autorisée de s\'associer à l\'interface de niveau supérieur d\'un écran à distance. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associer à un service widget"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet à une application d\'utiliser n\'importe quel décodeur installé pour lire les fichiers multimédias."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gérer les certificats de confiance"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet à l\'application d\'installer et de désinstaller les certificats CA en tant que certificats de confiance."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"exécuter l\'application lorsque l\'appareil est inactif"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cette autorisation permet au système Android d\'exécuter l\'application en arrière-plan lorsque l\'appareil est inactif."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"exécuter les tâches en arrière-plan planifiées de l\'application"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Cette autorisation permet au système Android d\'exécuter l\'application en arrière-plan sur demande."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"Lecture/écriture dans les ressources appartenant aux diagnostics"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet à l\'application d\'obtenir des droits en lecture/écriture concernant toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers du répertoire /dev). Ceci peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou l\'opérateur."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activer ou désactiver les composants de l\'application"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Autoriser l\'application à enregistrer et à rediriger les sorties audio"</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Détection de mot clé"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permet à l\'application de capturer du contenu audio pour détecter des mots clés. L\'enregistrement peut se produire en arrière-plan, sans désactiver les autres services de capture audio (tels que ceux d\'un caméscope)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Routage de l\'audio"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Permettre à l\'application de contrôler directement le routage de l\'audio et de remplacer les décisions relatives aux règles concernant l\'audio"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"enregistrer les sorties vidéo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Autoriser l\'application à enregistrer et à rediriger les sorties vidéo"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"enregistrer les sorties vidéo sécurisées"</string>
@@ -1171,7 +1175,7 @@
<string name="chooseUsbActivity" msgid="6894748416073583509">"Sélectionnez une application pour le périphérique de stockage USB"</string>
<string name="noApplications" msgid="2991814273936504689">"Aucune application ne peut effectuer cette action."</string>
<string name="aerr_title" msgid="1905800560317137752"></string>
- <string name="aerr_application" msgid="932628488013092776">"L\'application \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" s\'est arrêtée."</string>
+ <string name="aerr_application" msgid="932628488013092776">"\"<xliff:g id="APPLICATION">%1$s</xliff:g>\" s\'est arrêté."</string>
<string name="aerr_process" msgid="4507058997035697579">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> s\'est interrompu."</string>
<string name="anr_title" msgid="4351948481459135709"></string>
<string name="anr_activity_application" msgid="1904477189057199066">"L\'application <xliff:g id="APPLICATION">%2$s</xliff:g> ne répond pas.\n\nVoulez-vous quitter ?"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permet à une application de contrôler la protection des touches."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Détecter les modifications de l\'état de confiance"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permettre à une application de détecter les modifications de l\'état de confiance."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Fournir un agent de confiance"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permettre à une application de fournir un agent de confiance"</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"S\'associer à un service d\'agent de confiance"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permettre à une application de s\'associer à un service d\'agent de confiance."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagir avec le système de récupération et de mise à jour"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index f9bd61a..470ec41 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android सिस्टम"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"व्यक्तिगत"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"कार्यालय"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"व्यक्तिगत ऐप्स"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android कार्य"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"वे सेवाएं जिन पर आप खर्चा करते हैं"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ऐसे कार्य करें जिससे आपका धन खर्च हो सकता है."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"आपके संदेश"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"धारक को किसी वॉलपेपर के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"किसी ध्वनि सहभागिताकर्ता से आबद्ध हों"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"धारक को किसी ध्वनि सहभागिता सेवा के शीर्ष-स्तर के इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"ध्वनि कीफ़्रेज़ प्रबंधित करें"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"धारक को ध्वनि हॉटवर्ड पहचान के लिए कीफ़्रेज़ प्रबंधित करने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"रिमोट डिस्प्ले से आबद्ध करें"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"धारक को किसी रिमोट डिस्प्ले के शीर्ष-स्तरीय इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"किसी विजेट सेवा से आबद्ध करें"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ऐप्स को प्लेबैक डीकोड करने के लिए किसी भी इंस्टॉल किए गए डीकोडर का उपयोग करने देता है."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"विश्वसनीय क्रेडेंशियल प्रबंधित करें"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"ऐप्स को CA प्रमाणपत्रों को विश्वसनीय क्रेडेंशियल के रूप में इंस्टॉल और अनइंस्टॉल करने दें"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"निष्क्रिय समय के दौरान एप्लिकेशन चलाएं"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"यह अनुमति Android सिस्टम को उपकरण के उपयोग में नहीं रहने पर एप्लिकेशन को पृष्ठभूमि में चलाने देती है."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"एप्लिकेशन का शेड्यूल किया गया पृष्ठभूमि कार्य चलाएं"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"यह अनुमति Android सिस्टम को, अनुरोध किए जाने पर एप्लिकेशन को पृष्ठभूमि में चलाने देती है."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"निदान के स्वामित्व वाले संसाधनों को पढ़ें/लिखें"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"ऐप्स को diag समूह के स्वामित्व वाले किसी संसाधन को पढ़ने और उसमें लिखने देता है; उदाहरण के लिए, /dev की फ़ाइलें. यह सिस्टम की स्थिरता और सुरक्षा को संभावित रूप से प्रभावित कर सकता है. इसका उपयोग निर्माता या ऑपरेटर द्वारा केवल हार्डवेयर-विशिष्ट निदान के लिए किया जाना चाहिए."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ऐप्स घटकों को सक्षम या अक्षम करें"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ऐप्स को ऑडियो आउटपुट को कैप्चर और रीडायरेक्ट करने देता है."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"हॉटवर्ड पहचान"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"एप्लिकेशन को हॉटवर्ड पहचान के लिए ऑडियो कैप्चर करने देती है. कैप्चर पृष्ठभूमि में हो सकता है लेकिन वह अन्य ऑडियो कैप्चर (उदा. कैमकॉर्डर) को नहीं रोकता."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"ऑडियो रूटिंग"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"ऐप्स को ऑडियो रूटिंग पर प्रत्यक्ष नियंत्रण करने देती है और ऑडियो नीति निर्णयों को ओवरराइड करने देती है."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"वीडियो आउटपुट को कैप्चर करें"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"ऐप्स को वीडियो आउटपुट को कैप्चर और रीडायरेक्ट करने देता है."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"सुरक्षित वीडियो आउटपुट को कैप्चर करें"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"ऐप्स को कीगार्ड नियंत्रित करने देती है."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"ट्रस्ट स्थिति बदलावों को सुनें."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"किसी एप्लिकेशन को ट्रस्ट स्थिति के बदलावों को सुनने की अनुमति देती है."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"विश्वसनीय एजेंट प्रदान करें."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"एप्लिकेशन को विश्वसनीय एजेंट प्रदान करने देती है."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"विश्वस्त एजेंट सेटिंग मेनू लॉन्च करें."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"एप्लिकेशन को ऐसी गतिविधि लॉन्च करने की अनुमति मिलती है जो विश्वस्त एजेंट के व्यवहार में बदलाव लाती है."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ट्रस्ट एजेंट सेवा से आबद्ध करना"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"किसी एप्लिकेशन को ट्रस्ट एजेंट सेवा से आबद्ध करने की अनुमति देती है."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"अपडेट और पुनर्प्राप्ति सिस्टम के साथ सहभागिता करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 2adaaf1..7dc8e19 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sustav Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Osobno"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Posao"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Osobne aplikacije"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android za posao"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Usluge koje se plaćaju"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Radite stvari koje će uzrokovati novčane troškove."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vaše poruke"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Nositelju omogućuje povezivanje sa sučeljem pozadinske slike najviše razine. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"povezivanje s uslugom glasovne interakcije"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Vlasniku omogućuje povezivanje sa sučeljem najviše razine usluge glasovne interakcije. Nije potrebno za normalne aplikacije."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"upravljanje glasovnim ključnim frazama"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Omogućuje korisniku upravljanje ključnim frazama za otkrivanje glasovnih pokretača značajke. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vezanje uz udaljeni zaslon"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Nositelju omogućuje vezanje uza sučelje najviše razine udaljenog zaslona. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vezanje na uslugu widgeta"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Aplikaciji omogućuje korištenje bilo kojim instaliranim dekoderom medija za dekodiranje radi reprodukcije."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"upravljanje pouzdanim vjerodajnicama"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Omogućuje aplikaciji instaliranje i deinstaliranje CA certifikata kao pouzdanih vjerodajnica."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"izvodi aplikaciju tijekom mirovanja"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To dopuštenje omogućuje sustavu Android da izvodi aplikaciju u pozadini dok se uređaj ne upotrebljava."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"izvršavaj planirani rad aplikacije u pozadini"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"To dopuštenje omogućuje sustavu Android izvođenje aplikacije u pozadini na zahtjev."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"pisanje/čitanje u resursima čije je vlasnik dijagnostika"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Aplikaciji omogućuje čitanje i pisanje na bilo koji resurs u vlasništvu dijag. grupe; na primjer, datoteke u sustavu /dev. To bi moglo utjecati na stabilnost sustava i sigurnost. Dozvolu bi trebao upotrebljavati proizvođač ili operater SAMO za dijagnostiku koja se odnosi na hardver."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"omogućavanje ili onemogućavanje komponenti aplikacije"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Omogućuje aplikaciji primanje i preusmjeravanje audioizlaza."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Otkrivanje pokretača značajke"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Aplikaciji omogućuje snimanje zvuka radi otkrivanja pokretača značajke. Snimanje se može odvijati u pozadini, ali ne sprječava drugo snimanje zvuka (npr. kameru)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Preusmjeravanje zvučnog zapisa"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Omogućuje aplikaciji izravno upravljanje preusmjeravanjem zvučnog zapisa i zaobilaženje odluka pravila o zvučnim zapisima."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"primanje videoizlaza"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Omogućuje aplikaciji primanje i preusmjeravanje videoizlaza."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"primanje sigurnog videoizlaza"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Omogućuje aplikaciji upravljanje zaključavanjem tipkovnice."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Prati promjene pouzdanog stanja."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Omogućuje aplikaciji praćenje promjena pouzdanog stanja."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Pružanje agenta za pouzdanost."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Omogućuje aplikaciji pružanje agenta za pouzdanost."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Povezivanje s uslugom pouzdanog predstavnika"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Omogućuje aplikaciji povezivanje s uslugom pouzdanog predstavnika."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interakcija s ažuriranjem i sustavom za oporavak"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 45573e6..2582737 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android rendszer"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Személyes"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Munkahelyi"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Személyes alkalmazások"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Munkahelyi Android"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Fizetős szolgáltatások"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Olyan dolgok végrehajtása, amelyek pénzbe kerülnek."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Saját üzenetek"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lehetővé teszi, hogy a tulajdonos kötelezővé tegye egy háttérkép legfelső szintű felületét. A normál alkalmazásoknak erre soha nincs szüksége."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"csatlakozás egy hangvezérlőhöz"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Lehetővé teszi a használó számára, hogy csatlakozzon egy hangvezérlő szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"hangalapú kulcskifejezések kezelése"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"A használó kezelheti a hangalapú hotwordök felismerésére szolgáló kulcskifejezéseket. Az átlagos alkalmazásoknak nem lehet rá szükségük."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"csatlakozás egy távoli kijelzőhöz"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lehetővé teszi a használó számára, hogy csatlakozzon egy távoli kijelző legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"csatlakozás modulszolgáltatáshoz"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Lehetővé teszi egy alkalmazás számára bármely telepített médiadekóder használatát a lejátszás dekódolásához."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"megbízható tanúsítványok kezelése"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lehetővé teszi az alkalmazás számára a CA tanúsítványok telepítését és eltávolítását."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"alkalmazás futtatása tétlen időszakban"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ezzel az engedéllyel az Android a háttérben futtathatja az alkalmazást, amikor az eszközt nem használják."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"az alkalmazás ütemezett műveleteinek futtatása a háttérben"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Az engedély lehetővé teszi az Android számára, hogy kérés esetén a háttérben futtassa az alkalmazást."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"a diag tulajdonában lévő erőforrások olvasása és írása"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Lehetővé teszi egy alkalmazás számára, hogy olvassa és írja a diagnosztikai csoport minden erőforrását, például a /dev könyvtárban lévő fájlokat. Ez potenciálisan befolyásolhatja a rendszer stabilitását és biztonságát, ezért CSAK a gyártó vagy a szolgáltató használhatja hardverspecifikus diagnosztizálásra."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"alkalmazáskomponensek be- és kikapcsolása"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Engedélyezi az alkalmazásnak a hangkimenet rögzítését és átirányítását."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Hotwordérzékelés"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Lehetővé teszi, hogy alkalmazás rögzítse a befelé jövő hangokat hotwordérzékelés céljából. A rögzítés végbemehet a háttérben, és nem zavarja a más jellegű hangrögzítést, például a kamera esetében."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Hangirányítás"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Lehetővé teszi az alkalmazás számára, hogy kezelje a hangirányítást, illetve felülírja a hangra vonatkozó irányelvi döntéseket."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"videokimenet rögzítése"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Engedélyezi az alkalmazásnak a videokimenet rögzítését és átirányítását."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"biztonságos videokimenet rögzítése"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Lehetővé teszi egy alkalmazás számára a billentyűzár vezérlését."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Trust-állapot változásának figyelése"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Lehetővé teszi, hogy az alkalmazás figyelje a trust-állapot változásait."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Trust agent szoftver megadása"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Lehetővé teszi, hogy az alkalmazás megadjon egy trust agent szoftvert."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Trust agent szoftver beállításmenüjének indítása."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Lehetővé teszi az alkalmazások számára olyan tevékenységek indítását, amelyek megváltoztatják a trust agent szoftver viselkedését."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Csatlakozás egy trust agent szolgáltatáshoz"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Lehetővé teszi, hogy az alkalmazás egy trust agent szolgáltatáshoz csatlakozzon."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Kapcsolatfelvétel a frissítési és helyreállítási rendszerrel"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 2d72f06..f0bee2b 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Անձնական"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Աշխատանքային"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Անձնական ծրագրեր"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Ծառայություններ, որոնց համար կգանձվեք"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Կատարել գործողություններ, որի դիմաց ձեր հաշվից գումար կծախսվի:"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Ձեր հաղորդագրությունները"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Թույլ է տալիս սեփականատիրոջը միանալ պաստառի վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"կապվել ձայնային փոխազդիչին"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Թույլ է տալիս սեփականատիրոջը միանալ ձայնային փոխազդիչի բազային միջերեսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"կառավարել ձայնային բանալի բառակապակցությունները"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Սեփականատիրոջը թույլ է տալիս կառավարել բանալի բառակապակցությունները՝ ձայնային թեժ բառերի հայտնաբերման համար: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"միանալ հեռակա էկրանին"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Թույլ է տալիս սեփականատիրոջը միանալ հեռակա էկրանի վերին մակարդակի ինտերֆեյսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"միանալ վիջեթ ծառայությանը"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Թույլ է տալիս հավելվածին օգտագործել ցանկացած տեղադրված մեդիա վերծանիչ` նվագարկումը ապակոդավորելու համար:"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"կառավարել վստահելի հավաստագրերը"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Թույլատրում է հավելվածին տեղադրել և ապատեղադրել CA վկայագրերը՝ որպես վստահելի հավաստագրեր:"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"գործադրել ծրագրեր պարապուրդի ժամանակ"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Այս թույլտվությունը հնարավորություն է տալիս, որ Android համակարգը ծրագրեր գործադրի ֆոնային ռեժիմում, երբ սարքը չի օգտագործվում:"</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"աշխատեցնել ծրագրի ֆոնային ռեժիմում պլանավորված աշխատանքը"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Այս թույլտվության շնորհիվ Android համակարգն անհրաժեշտության դեպքում կարող է աշխատեցնել ծրագիրը ֆոնային ռեժիմում:"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"կարդալ կամ գրել ախտորոշիչին պատկանող ռեսուրսները"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Թույլ է տալիս հավելվածին կարդալ և գրել ախտորոշիչ խմբին պատկանող ցանկացած ռեսուրսում, ինչպես օրինակ ֆայլերը /dev-ում: Դա կարող է ազդել համակարգի կայունության և անվտանգության վրա: Սա պետք է օգտագործել միայն արտադրողի կամ օպերատորի կողմից սարքին հատուկ ախտորոշման համար:"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"միացնել կամ անջատել հավելվածի բաղադրիչները"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Թույլ է տալիս ծրագրին պահել և վերահղել աուդիո արտածումը:"</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Թեժ բառի հայտնաբերում"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Հավելվածին թույլ է տալիս որսալ ձայնանյութը՝ թեժ բառի հայտնաբերման համար: Դա կարող է տեղի ունենալ հետնաշերտում, սակայն չի խանգարի այլ աուդիո ձայնագրություններին (օր.՝ Տեսախցիկից):"</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Աուդիո երթուղայնացում"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Ծրագրին թույլ է տալիս անմիջականորեն վերահսկել աուդիո երթուղայնացումը և վերասահմանել աուդիո քաղաքականության որոշումները:"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"պահել վիդեո արտածումը"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Թույլ է տալիս ծրագրին պահել և վերահղել վիդեո արտածումը:"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"պահել անվտանգ վիդեո արտածումը"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Թույլ է տալիս հավելվածին կառավարել ստեղնաշարի պաշտպանիչը:"</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Լսել վստահության կարգավիճակի փոփոխությունները:"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Ծրագրին թույլ է տալիս լսել վստահության կարգավիճակի փոփոխությունները:"</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Տրամադրել վստահելի գործակալ:"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Ծրագրին թույլ է տալիս տրամադրել վստահելի գործակալ:"</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Կապվել վստահելի գործակալի ծառայությանը"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ծրագրին թույլ է տալիս կապվել վստահելի գործակալի ծառայությանը:"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Փոխազդել թարմացման և վերականգնման համակարգի հետ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 3d619b9..9dca8a5 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Pribadi"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Kantor"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Aplikasi pribadi"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Layanan berbayar"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Lakukan hal yang dapat dikenai biaya."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Pesan Anda"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu wallpaper. Tidak pernah diperlukan oleh apl normal."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"mengikat ke pemicu interaksi suara"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Memungkinkan pemegang mengikat antarmuka tingkat tinggi dari layanan interaksi suara. Tidak pernah diperlukan oleh aplikasi normal."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"mengelola frasa kunci suara"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Memungkinkan pemegang mengelola frasa kunci untuk deteksi kata cepat suara. Tidak pernah diperlukan oleh aplikasi normal."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"mengikat ke layar jarak jauh"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Mengizinkan pemegang mengikat ke antarmuka tingkat atas dari layar jarak jauh. Tidak pernah diperlukan untuk aplikasi normal."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"mengikat ke layanan widget"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Mengizinkan apl menggunakan pengawasandi media apa pun yang terpasang guna mengawasandikan media untuk diputar."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"kelola kredensial tepercaya"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Izinkan aplikasi memasang dan mencopot pemasangan sertifikat CA sebagai kredensial tepercaya."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"menjalankan aplikasi selama waktu nganggur"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Izin ini memungkinkan sistem Android menjalankan aplikasi di latar belakang saat perangkat tidak digunakan."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"jalankan pekerjaan latar belakang yang terjadwal milik aplikasi"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Izin ini memungkinkan sistem Android menjalankan aplikasi di latar belakang saat diminta."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"baca/tulis ke sumber daya yang dimiliki oleh diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Mengizinkan apl membaca dan menulis ke sumber daya apa pun yang dimiliki oleh grup diag; misalnya, file dalam /dev. Izin ini berpotensi memengaruhi kestabilan dan keamanan sistem. Sebaiknya ini HANYA digunakan untuk diagnosis khusus perangkat keras oleh pabrikan atau operator."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"mengaktifkan atau menonaktifkan komponen apl"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Memungkinkan aplikasi menangkap dan mengalihkan keluaran audio."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Deteksi kata cepat"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Memungkinkan aplikasi menangkap audio untuk deteksi Kata Cepat. Penangkapan dapat berlangsung di latar belakang namun tidak akan mencegah penangkapan audio yang lain (misalnya Perekam video)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Perutean Audio"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Memungkinkan aplikasi mengontrol perutean audio dan mengganti keputusan kebijakan audio secara langsung."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"tangkap keluaran video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Memungkinkan aplikasi menangkap dan mengalihkan keluaran video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"tangkap keluaran video aman"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Izinkan aplikasi untuk mengontrol pengaman."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Dengarkan perubahan status kepercayaan."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Mengizinkan aplikasi mendengarkan perubahan dalam status kepercayaan."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Berikan agen tepercaya."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Memungkinkan aplikasi memberikan agen tepercaya."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Luncurkan menu setelan agen tepercaya."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Memungkinkan aplikasi meluncurkan aktivitas yang mengubah perilaku agen tepercaya."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Ikat ke layanan agen kepercayaan"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Mengizinkan aplikasi mengikat ke layanan agen kepercayaan."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Berinteraksi dengan sistem pemulihan dan pembaruan"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9a26b62..0ea6f6e 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personale"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Lavoro"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"App personali"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servizi che prevedono un costo"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Svolgono operazioni che possono comportare un costo."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"I tuoi messaggi"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Consente l\'associazione di uno sfondo all\'interfaccia principale. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"collegamento a un servizio di interazione vocale"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio di interazione vocale. Non dovrebbe essere mai necessaria per le normali app."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gestione delle frasi chiave vocali"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Consente al titolare di gestire le frasi chiave per il rilevamento hotword vocale. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"collega a un display remoto"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un display remoto. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associazione a un servizio widget"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Consente all\'applicazione di utilizzare qualsiasi decoder multimediale installato per la decodifica ai fini della riproduzione."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestione di credenziali attendibili"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Consente all\'app di installare e disinstallare certificati CA come credenziali attendibili."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"esegui l\'applicazione nel tempo di inattività del sistema"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Questa autorizzazione consente al sistema Android di eseguire l\'applicazione in background mentre il dispositivo non è in uso."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"esegui operazioni pianificate in background dell\'applicazione"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Questa autorizzazione consente al sistema Android di eseguire l\'applicazione in background quando richiesto."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lettura/scrittura risorse di proprietà di diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Consente all\'applicazione di leggere le risorse del gruppo diag e scrivere in esse, ad esempio i file in /dev. Ciò potrebbe influire su stabilità e sicurezza del sistema. Dovrebbe essere utilizzata SOLTANTO per diagnostiche specifiche dell\'hardware effettuate dal produttore o dall\'operatore."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"attivazione/disattivazione componenti applicazioni"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Consente all\'app di acquisire e reindirizzare l\'uscita audio."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Rilevamento hotword"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Consente all\'app di acquisire l\'audio per il rilevamento Hotword. L\'acquisizione può avvenire in background ma non impedisce l\'acquisizione di altro audio (ad esempio con la videocamera)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Routing dell\'audio"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Consente all\'app di controllare direttamente il routing audio e di sostituire le impostazioni delle norme per l\'audio."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"acquisizione dell\'uscita video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Consente all\'app di acquisire e reindirizzare l\'uscita video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"acquisizione dell\'uscita video sicura"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Consente a un\'applicazione di controllare keguard."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Rilevamento modifiche dello stato trust."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Consente a un\'applicazione di rilevare le modifiche nello stato trust."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Indica un trust agent."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Consente a un\'applicazione di indicare un trust agent."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Avvio del menu di impostazioni del trust agent."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Consente a un\'applicazione di avviare un\'attività che modifica il comportamento del trust agent."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Associazione a un servizio trust agent"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Consente a un\'applicazione di associarsi a un servizio trust agent."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interazione con il sistema di ripristino e aggiornamento"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 5c47131..19fb05a 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
<string name="android_system_label" msgid="6577375335728551336">"מערכת Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"אישי"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"עבודה"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"אפליקציות אישיות"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android לעבודה"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"שירותים שעולים כסף"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ביצוע פעולות שעשויות לעלות לך כסף."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"ההודעות שלך"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של טפט. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"איגוד לשירות אינטראקציה קולית"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"מאפשרת לבעלים לאגד לממשק ברמה העליונה של שירות אינטראקציה קולית. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"ניהול של ביטויי מפתח קוליים"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"מאפשרת לבעלים לנהל את ביטויי המפתח עבור זיהוי של מילת הפעלה. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"איגוד לצג מרוחק"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של צג רחוק. לעולם אינה אמורה להיות נחוצה לאפליקציות רגילות."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"הכפפה לשירות Widget"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"הרשאה זו מאפשרת לאפליקציה להשתמש בכל מפענח מדיה מותקן כדי לבצע פענוח להשמעה."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"ניהול פרטי כניסה מהימנים"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"מאפשרת לאפליקציה להתקין ולהסיר אישורי CA כפרטי כניסה מהימנים."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"הרצת אפליקציה בזמן מצב לא פעיל"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ההרשאה הזו מאפשרת למערכת Android להריץ את האפליקציה ברקע כשהמכשיר אינו בשימוש."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"הרץ את העבודה ברקע המתוזמנת של האפליקציה"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"ההרשאה הזו מאפשרת למערכת Android להריץ את האפליקציה ברקע כשהפעולה מתבקשת."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"קרא/כתוב במשאבים בבעלות diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"מאפשר לאפליקציה לקרוא ולכתוב בכל משאב שבבעלות קבוצת ה-diag; לדוגמה, קבצים ב-/dev. פעולה זו עשויה להשפיע על היציבות והאבטחה של המערכת. אפשרות זו צריכה לשמש רק את היצרן או המפעיל, לצורך אבחונים ספציפיים לחומרה."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"הפעלה או השבתה של רכיבי אפליקציות"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"מאפשרת לאפליקציה לקלוט ולהפנות מחדש פלט אודיו."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"זיהוי של מילת הפעלה"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"מאפשרת לאפליקציה לקלוט אודיו עבור זיהוי של מילת הפעלה. פעולת הקליטה יכולה להתבצע ברקע, אבל לא מונעת קליטת אודיו אחרת (למשל, במצלמת הווידאו)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"ניתוב אודיו"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"מאפשר לאפליקציה לשלוט באופן ישיר בניתוב אודיו ולעקוף החלטות מדיניות עבור אודיו."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"קליטת פלט וידאו"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"מאפשרת לאפליקציה לקלוט ולהפנות מחדש פלט וידאו."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"קליטת פלט וידאו מאובטח"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"מאפשר לאפליקציה לשלוט במגן המקלדת."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"חיפוש שינויים במצב אמון."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"מאפשר לאפליקציה לחפש שינויים במצב אמון."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"ציון סוכן אמון."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"מאפשר לאפליקציה לספק סוכן אמון."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"הפעלת תפריט ההגדרות של סוכן האמון."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"מאפשר לאפליקציה להתחיל פעילות המשנה את ההתנהגות של סוכן האמון."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"איגוד אל שירות סוכן אמון"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"מאפשר לאפליקציה לאגוד אל שירות סוכן אמון."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"אינטראקציה עם מערכת שחזור ועדכונים"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 6d35633..6ba99bf 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
<string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"プライベート"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"職場"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"プライベートアプリ"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"料金の発生するサービス"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"料金発生の可能性がある操作を実行します。"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"送受信したメッセージ"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"壁紙のトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"音声対話サービスへのバインド"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"音声対話サービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"音声キーフレーズの管理"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"音声注目ワードの認識用キーフレーズを管理することを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"リモートディスプレイへのバインド"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"リモートディスプレイのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ウィジェットサービスにバインド"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"インストール済みのメディアデコーダーを使用して再生用にデコードすることをアプリに許可します。"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"信頼できる認証情報の管理"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"CA証明書を信頼できる認証情報としてインストールしたりアンインストールしたりすることをアプリに許可します。"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"アイドル状態でのアプリの実行"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"この権限により、端末が使用中でない場合でもAndroidシステムがバックグラウンドでアプリを実行できるようになります。"</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"アプリの予定されたバックグラウンド作業の実行"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"この権限により、リクエストされるとAndroidシステムがバックグラウンドでアプリを実行できるようになります。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"diagが所有するリソースの読み書き"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"diagグループが所有するリソース(/dev内のファイルなど)の読み書きをアプリに許可します。許可すると、システムの安定性とセキュリティに影響が生じる可能性があります。メーカー/通信事業者によるハードウェア固有の診断以外には使用しないでください。"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"アプリのコンポーネントの有効/無効化"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"音声出力のキャプチャとリダイレクトをアプリに許可します。"</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"注目ワード検出"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"注目ワード検出での音声キャプチャをアプリに許可します。キャプチャはバックグラウンドで発生しますが、その他の音声キャプチャ(例: ビデオ録画)を妨げることはありません。"</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"オーディオルーティング"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"オーディオルーティングの直接制御とオーディオポリシー決定の上書きをアプリに許可します。"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"動画出力のキャプチャ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"動画出力のキャプチャとリダイレクトをアプリに許可します。"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"セキュリティ保護された動画出力のキャプチャ"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"キーガードの制御をアプリに許可します。"</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"信頼状態の変更をリッスン"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"信頼状態の変更をリッスンすることをアプリに許可します。"</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"信頼できるエージェントの提供"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"信頼できるエージェントの提供をアプリに許可します。"</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"信頼できるエージェントの設定メニューの起動"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"信頼できるエージェントの動作を変更するアクティビティを開始することをアプリに許可します。"</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"信頼できるエージェントサービスへのバインド"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"信頼できるエージェントサービスにバインドすることをアプリに許可します。"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"アップデートと回復システムへのアクセス"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 770c14d..879d00f 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-ის სისტემა"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"პირადი"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"სამსახური"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"პერსონალური აპები"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android სამსახურისთვის"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"სერვისები, რომელშიც ფულის გადახდა გიწევთ"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ისეთი აქტივობების განხორციელება, რომლებშიც ფულის გადახდა მოგიწევთ."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"თქვენი შეტყობინებები"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"მფლობელს შეეძლება ფონის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"ხმის ინტერაქტორთან შეკავშირება"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"მფლობელს შეეძლება შეკავშირდეს ხმის ინტერაქციის სერვისების ზედა დონის ინტერფეისთან. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დასჭირდეს."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"ხმოვანი საიდუმლო ფრაზების მართვა"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"საშუალებას აძლევს მფლობელს მართოს საიდუმლო ფრაზები ხმოვანი ჯადოსნური სიტყვის ამოცნობისათვის. ეს ჩვეულებრივ აპებს არ უნდა დაჭირდეს."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"დისტანციურ მონიტორზე მიბმა"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"მფლობელს შეეძლება მიებას დისტანციურ მონიტორის ზედა დონის ინტერფეისს. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დაჭირდეს."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ვიჯეტ სერვისთან დაკავშირება"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"აპს დასაკრავად შეეძლება გამოიყენოს ნებისმიერი დაყენებული მედია დეკოდერი."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"სანდო მტკიცებულებების მართვა"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"აპისთვის ნების დართვა, მოახდინოს CA სერტიფიკატების სანდო მტკიცებულებებად ინსტალაცია და დეინსტალაცია."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"უქმე მდგომარეობისას აპლიკაციის გაშვება"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ეს უფლება Android-ის სისტემას უფლებას ანიჭებს ფონურად გაუშვას აპლიკაცია, როდესაც მოწყობილობა არ გამოიყენება."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"აპლიკაციის დაგეგმილი ფონური სამუშაოს გაშვება"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"ეს ნებართვა Android-ის სისტემას საშუალებას აძლევს მოთხოვნისას ფონში გაუშვას აპლიკაცია."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"სისტემის დიაგნოსტიკის რესურსებში წაკითხვა/ჩაწერის უფლება"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"აპს შეეძლება, წაიკითხოს ან ჩაწეროს ნებისმიერ რესურსში, რომელიც დიაგნოსტიკის ჯგუფს ეკუთვნის, მაგალითად, ფაილები /dev-ში. ამან შესაძლოა იმოქმედოს სისტემის სტაბილურობასა და უსაფრთხოებაზე. მისი გამოყენება მხოლოდ მწარმოებლის ან ოპერატორის მიერ ტექნიკის სპეციფიკური დიაგნოსტიკისთვის უნდა მოხდეს."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"აპის კომპონენტების ჩართვა ან გამორთვა"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"საშუალებას აძლევს აპს დაიჭიროს და გადაამისამართოს გამომავალი აუდიო."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ჯადოსნური სიტყვის პოვნა"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"საშუალებას აძლევს აპს ჩაიწეროს აუდიო ჯადოსნური სიტყვების ამოცნობისათვის. ჩაწერა შესაძლოა განხორციელდეს ფონურად, თუმცა ხელს არ უშლის სხვა სახის აუდიოს ჩაწერას (მაგ. ვიდეოჩამწერიდან)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"აუდიო მარშრუტიზაცია"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"საშუალებას აძლევს აპს პირდაპირ აკონტროლოს აუდიო მარშრუტიზაცია უკუაგდოს აუდიო პოლისის გადაწყვეტილებები."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"გამომავალი ვიდეოს დაჭერა"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"საშუალებას აძლევს აპს დაიჭიროს და გადაამისამართოს გამომავალი ვიდეო."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"გამომავალი დაცული ვიდეოს დაჭერა"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"აპლიკაციას შეეძლება ღილაკების დამცავის კონტროლი."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"ნდობის მდგომარეობის ცვლილებების მოსმენა."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"საშუალებას აძლევს აპლიკაციას მოუსმინოს ცვლილებებს სანდო მდგომარეობაში."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"სანდო აგენტის წარმოდგენა."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"საშუალებას აძლევს აპლიკაციას წარმოადგინოს სანდო აგენტი."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"სანდო აგენტის სერვისზე მიმაგრება."</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"საშუალებას აძლევს აპლიკაციას მიემაგროს სანდო აგენტის სერვისს."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"განახლებასთან და აღდგენის სისტემასთან ინტერაქცია"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index dbe2d7f..daf004c 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"របៀបសុវត្ថិភាព"</string>
<string name="android_system_label" msgid="6577375335728551336">"ប្រព័ន្ធ Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"ផ្ទាល់ខ្លួន"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"កន្លែងធ្វើការ"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"កម្មវិធីផ្ទាល់ខ្លួន"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"សេវាកម្មដែលកាត់លុយរបស់អ្នក"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ធ្វើអ្វីដែលអាចកាត់លុយរបស់អ្នក។"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"សាររបស់អ្នក"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃផ្ទាំងរូបភាព។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"ភ្ជាប់ទៅអ្នកសហការសំឡេង"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"អនុញ្ញាតឲ្យម្ចាស់ភ្ជាប់ទៅចំណុចប្រទាក់កម្រិតកំពូលរបស់សេវាកម្មអន្តរកម្មសំឡេង។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"គ្រប់គ្រងឃ្លាសំឡេង"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"អនុញ្ញាតឲ្យម្ចាស់គ្រប់គ្រងឃ្លាសម្រាប់ការរកឃើញពាក្យជាសំឡេង។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ភ្ជាប់ទៅការបង្ហាញពីចម្ងាយ"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"អនុញ្ញាតឲ្យម្ចាស់ភ្ជាប់ទៅចំណុចប្រទាក់កម្រិតកំពូលនៃការបង្ហាញពីចម្ងាយ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ចងសេវាកម្មធាតុក្រាហ្វិក"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ឲ្យកម្មវិធីប្រើកម្មវិធីឌិកូដមេឌៀដែលបានដំឡើង ដើម្បីឌិកូដសម្រាប់ការចាក់ឡើងវិញ។"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"គ្រប់គ្រងព័ត៌មានសម្ងាត់ដែលទុកចិត្ត"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"អនុញ្ញាតឲ្យកម្មវិធីដំឡើង និងលុបវិញ្ញាបនបត្រ CA នៅពេលមានព័ត៌មានសម្ងាត់ដែលទុកចិត្ត។"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"ដំណើរការកម្មវិធីអំឡុងពេលទំនេរ"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"សិទ្ធិនេះអនុញ្ញាតឲ្យប្រព័ន្ធ Android ដំណើរការកម្មវិធីក្នុងផ្ទៃខាងក្រោយ ខណៈដែលឧបករណ៍មិនកំពុងប្រើ។"</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"ដំណើរការការងារក្នុងផ្ទៃខាងក្រោយដែលបានកំណត់ពេលវេលាសម្រាប់កម្មវិធី"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"សិទ្ធិនេះអនុញ្ញាតឲ្យប្រព័ន្ធ Android ដំណើរការកម្មវិធីក្នុងផ្ទៃខាងក្រោយពេលបានស្នើ។"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"អាន/សរសេរធនធានគ្រប់គ្រងប្រអប់"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"ឲ្យកម្មវិធីអាន និងសរសេរប្រភពណាមួយដែលគ្រប់គ្រងដោយក្រុមអ្នកវិនិច្ឆ័យ ឧទាហរណ៍ ឯកសារនៅក្នុង /dev ។ វាអាចប៉ះពាល់យ៉ាងខ្លាំងដល់ស្ថេរភាព និងសុវត្ថិភាពប្រព័ន្ធ។ វាគួរត្រូវបានប្រើសម្រាប់វិនិច្ឆ័យផ្នែករឹងជាក់លាក់ដោយក្រុមហ៊ុនផលិត ឬប្រតិបត្តិករ។"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"បិទ ឬបើកសមាសធាតុកម្មវិធី"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ឱ្យកម្មវិធីដើម្បីចាប់យក និងប្ដូរទិសលទ្ធផលអូឌីយ៉ូ។"</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ការរកឃើញពាក្យ"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"ឲ្យកម្មវិធីថតអូឌីយ៉ូសម្រាប់ការរកឃើញពាក្យ។ ការថតអាចកើតឡើងក្នុងផ្ទៃខាងក្រោយ ប៉ុន្តែមិនរារាំងការថតអូឌីយ៉ូផ្សេងទេ (ឧ. ម៉ាស៊ីនថតវីដេអូ)។"</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"ការនាំផ្លូវអូឌីយ៉ូ"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"ឲ្យកម្មវិធីពិនិត្យផ្លូវអូឌីយ៉ូដោយផ្ទាល់ ហើយបដិសេធការសម្រេចចិត្តគោលនយោបាយអូឌីយ៉ូ។"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"ចាប់យកលទ្ធផលវីដេអូ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"ឲ្យកម្មវិធីចាប់យក និងប្ដូរទិសលទ្ធផលវីដេអូ។"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ចាប់យកលទ្ធផលវីដេអូសុវត្ថិភាព"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"ឲ្យកម្មវិធីគ្រប់គ្រង keguard ។"</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"ស្ដាប់ការផ្លាស់ប្ដូរស្ថានភាពដែលទុកចិត្ត។"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"ឲ្យកម្មវិធីស្ដាប់ការផ្លាស់ប្ដូរក្នុងស្ថានភាពដែលទុកចិត្ត។"</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"ផ្ដល់ភ្នាក់ងារដែលទុកចិត្ត។"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"ឲ្យកម្មវិធីផ្ដល់ភ្នាក់ងារដែលទុកចិត្ត។"</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"ចាប់ផ្ដើមម៉ឺនុយការកំណត់ភ្នាក់ងារជឿទុកចិត្ត។"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"អនុញ្ញាតឲ្យកម្មវិធីចាប់ផ្ដើមសកម្មដែលផ្លាស់ប្ដូរឥរិយាបថភ្នាក់ងារជឿទុកចិត្ត។"</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ភ្ជាប់ទៅសេវាកម្មភ្នាក់ងារដែលទុកចិត្ត"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"ឲ្យកម្មវិធីភ្ជាប់សេវាកម្មភ្នាក់ងារដែលទុកចិត្ត។"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"អន្តរកម្មជាមួយបច្ចុប្បន្នភាព និងប្រព័ន្ធសង្គ្រោះ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 111f822..43d1b25 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"개인"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"직장"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"개인 앱"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"요금이 부과되는 서비스"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"요금이 부과될 수 있는 작업을 수행할 수 있도록 합니다."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"메시지"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"권한을 가진 프로그램이 배경화면에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"음성 상호작용 서비스 사용"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"권한을 가진 프로그램이 음성 상호작용 서비스의 최상위 인터페이스를 사용하도록 합니다. 일반 앱에는 필요하지 않습니다."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"음성 핵심문구 관리"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"권한을 가진 프로그램이 음성 핫워드 감지용 핵심문구를 관리할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"원격 디스플레이에 연결"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"권한을 가진 프로그램이 원격 디스플레이에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"위젯 서비스와 연결"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"애플리케이션에서 설치된 모든 미디어 디코더를 사용하여 재생하는 데 디코딩할 수 있도록 허용합니다."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"신뢰할 수 있는 자격증명 관리"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"앱에서 CA 인증서를 신뢰할 수 있는 자격증명으로 설치 및 제거하도록 허용합니다."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"유휴 시간 동안 애플리케이션 실행"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"이 권한을 부여하면 기기를 사용하지 않는 동안 Android 시스템이 백그라운드에서 애플리케이션을 실행할 수 있게 됩니다."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"애플리케이션의 예약된 백그라운드 작업 실행"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"이 권한을 부여하면 요청이 있을 경우 Android 시스템이 백그라운드에서 애플리케이션을 실행할 수 있게 됩니다."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"진단 그룹 소유의 리소스 읽기/쓰기"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"앱이 진단 그룹 소유의 리소스(예: /dev에 있는 파일)를 읽고 쓸 수 있도록 허용합니다. 이 기능은 시스템 안정성 및 보안에 영향을 미칠 수 있으므로 제조업체 또는 사업자가 하드웨어 관련 진단을 수행하는 경우에만 사용해야 합니다."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"앱 구성요소 사용 또는 사용 안함"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"앱이 오디오 출력을 캡처하고 리디렉션하도록 허용합니다."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"핫워드 감지"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"앱에서 핫워드 감지를 위해 오디오를 캡처하도록 허용합니다. 캡처는 백그라운드에서 수행될 수 있지만 다른 오디오 캡처를 차단하지 않습니다(예: 캠코더)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"오디오 라우팅"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"앱이 오디오 라우팅을 직접 제어하고 오디오 정책 결정을 무시할 수 있도록 허용합니다."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"동영상 출력 캡처"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"앱이 동영상 출력을 캡처하고 리디렉션하도록 허용합니다."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"안전한 동영상 출력 캡처"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"애플리케이션에서 키가드를 제어하도록 허용합니다."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Trust 상태 변경사항 수신"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"애플리케이션이 Trust 상태에서의 변경사항을 수신할 수 있도록 허용합니다."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Trust Agent 제공"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"애플리케이션이 Trust Agent를 제공할 수 있도록 허용합니다."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Trust Agent 서비스에 연결"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"애플리케이션이 Trust Agent 서비스에 바인딩할 수 있도록 허용합니다."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"업데이트 및 복구 시스템과 상호작용"</string>
diff --git a/core/res/res/values-land/dimens_quantum.xml b/core/res/res/values-land/dimens_material.xml
similarity index 85%
rename from core/res/res/values-land/dimens_quantum.xml
rename to core/res/res/values-land/dimens_material.xml
index 7789219..c8c95d7b 100644
--- a/core/res/res/values-land/dimens_quantum.xml
+++ b/core/res/res/values-land/dimens_material.xml
@@ -16,8 +16,8 @@
<resources>
<!-- Default height of an action bar. -->
- <dimen name="action_bar_default_height_quantum">48dp</dimen>
+ <dimen name="action_bar_default_height_material">48dp</dimen>
<!-- Default padding of an action bar. -->
- <dimen name="action_bar_default_padding_quantum">0dp</dimen>
+ <dimen name="action_bar_default_padding_material">0dp</dimen>
</resources>
diff --git a/core/res/res/values-large/themes_device_defaults.xml b/core/res/res/values-large/themes_device_defaults.xml
index d57e827..d252c27 100644
--- a/core/res/res/values-large/themes_device_defaults.xml
+++ b/core/res/res/values-large/themes_device_defaults.xml
@@ -31,18 +31,12 @@
===============================================================
-->
<resources>
- <style name="Theme.DeviceDefault.DialogWhenLarge"
- parent="@android:style/Theme.DeviceDefault.Dialog.FixedSize">
+ <style name="Theme.DeviceDefault.DialogWhenLarge" parent="@style/Theme.DeviceDefault.Dialog.FixedSize">
<item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
</style>
- <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar"
- parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar.FixedSize">
+ <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="@style/Theme.DeviceDefault.Dialog.NoActionBar.FixedSize">
<item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
</style>
- <style name="Theme.DeviceDefault.Light.DialogWhenLarge"
- parent="@android:style/Theme.DeviceDefault.Light.Dialog.FixedSize">
- </style>
- <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar"
- parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar.FixedSize">
- </style>
+ <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="@style/Theme.DeviceDefault.Light.Dialog.FixedSize" />
+ <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.DeviceDefault.Light.Dialog.NoActionBar.FixedSize" />
</resources>
diff --git a/core/res/res/values-large/themes.xml b/core/res/res/values-large/themes_holo.xml
similarity index 66%
rename from core/res/res/values-large/themes.xml
rename to core/res/res/values-large/themes_holo.xml
index 448e7c8..3f03932 100644
--- a/core/res/res/values-large/themes.xml
+++ b/core/res/res/values-large/themes_holo.xml
@@ -3,16 +3,16 @@
/*
** Copyright 2010, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
@@ -32,18 +32,12 @@
===============================================================
-->
<resources>
- <style name="Theme.Holo.DialogWhenLarge"
- parent="@android:style/Theme.Holo.Dialog.FixedSize">
+ <style name="Theme.Holo.DialogWhenLarge" parent="@style/Theme.Holo.Dialog.FixedSize">
<item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
</style>
- <style name="Theme.Holo.DialogWhenLarge.NoActionBar"
- parent="@android:style/Theme.Holo.Dialog.NoActionBar.FixedSize">
+ <style name="Theme.Holo.DialogWhenLarge.NoActionBar" parent="@style/Theme.Holo.Dialog.NoActionBar.FixedSize">
<item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
</style>
- <style name="Theme.Holo.Light.DialogWhenLarge"
- parent="@android:style/Theme.Holo.Light.Dialog.FixedSize">
- </style>
- <style name="Theme.Holo.Light.DialogWhenLarge.NoActionBar"
- parent="@android:style/Theme.Holo.Light.Dialog.NoActionBar.FixedSize">
- </style>
+ <style name="Theme.Holo.Light.DialogWhenLarge" parent="@style/Theme.Holo.Light.Dialog.FixedSize" />
+ <style name="Theme.Holo.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Holo.Light.Dialog.NoActionBar.FixedSize" />
</resources>
diff --git a/core/res/res/values-large/themes_material.xml b/core/res/res/values-large/themes_material.xml
new file mode 100644
index 0000000..2781608
--- /dev/null
+++ b/core/res/res/values-large/themes_material.xml
@@ -0,0 +1,40 @@
+<?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.
+-->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see themes_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+<resources>
+ <style name="Theme.Material.DialogWhenLarge" parent="@style/Theme.Material.Dialog.FixedSize">
+ <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+ </style>
+ <style name="Theme.Material.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Dialog.NoActionBar.FixedSize">
+ <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+ </style>
+ <style name="Theme.Material.Light.DialogWhenLarge" parent="@style/Theme.Material.Light.Dialog.FixedSize" />
+ <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Light.Dialog.NoActionBar.FixedSize" />
+</resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 3b275a5..e386a24 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"ລະບົບ Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"ສ່ວນໂຕ"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"ບ່ອນເຮັດວຽກ"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"ແອັບຯສ່ວນໂຕ"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"ບໍລິການທີ່ເຮັດໃຫ້ທ່ານເສຍເງິນ"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ເຮັດສິ່ງທີ່ທ່ານຕ້ອງເສຍຄ່າໃຊ້ຈ່າຍ."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"ຂໍ້ຄວາມຂອງທ່ານ"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ອະນຸຍາດໃຫ້ຜູ່ໃຊ້ເຊື່ອມໂຍງກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງພາບພື້ນຫຼັງໃດນຶ່ງ. ແອັບຯທຳມະດາບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"ເຊື່ອມໂຍງກັບຕົວຕິດຕໍ່ດ້ວຍສຽງ"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງສ່ວນຕິດຕໍ່ລະດັບສູງສຸດຂອງບໍລິການການຕິດຕໍ່ດ້ວຍສຽງ."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"ຈັດການລະຫັດສຽງ"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"ອະນຸຍາດໃຫ້ຈັດການລະຫັດສຳລັບການກວດພົບຄຳສັ່ງສຽງ. ແອັບຯທົ່ວໄປບໍ່ຄວນຕ້ອງໃຊ້."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ຜູກກັນເພື່ອສະແດງຜົນທາງໄກ."</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງການສະແດງຜົນທາງໄກ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ເຊື່ອມໂຍງໄປຫາບໍລິການວິດເຈັດ"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ອະນຸຍາດໃຫ້ແອັບຯໃຊ້ທຸກຕົວຖອດລະຫັດສື່ທີ່ຕິດຕັ້ງໄວ້ແລ້ວ ເພື່ອການຖອດລະຫັດການຫຼິ້ນໄຟລ໌ຕ່າງໆ."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"ຈັດການໜັງສືຮັບຮອງທີ່ເຊື່ອຖືໄດ້."</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"ອະນຸຍາດໃຫ້ແອັບຯ ຕິດຕັ້ງ ແລະ ຖອນການຕິດຕັ້ງໃບຢັ້ງຢືນ CA ທີ່ເປັນໃບຮັບຮອງທີ່ເຊື່ອຖືໄດ້."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"ເປີດແອັບພລິເຄຊັນໃນເວລາທີ່ບໍ່ເຮັດວຽກ"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ນີ້ຈະເປັນການອະນຸຍາດໃຫ້ລະບົບ Android ສາມາດເປີດແອັບພລິເຄຊັນໃນພື້ນຫຼັງໄດ້ໃນຂະນະທີ່ອຸປະກອນບໍ່ຖືກນຳໃຊ້."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"ເປີດແອັບພລິເຄຊັນເພື່ອເຮັດວຽກຕາມເວລາຢູ່ໃນພື້ນຫຼັງ"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"ສິດນີ້ອະນຸຍາດໃຫ້ລະບົບ Android ສາມາດເປີດແອັບພລິເຄຊັນໃນພື້ນຫຼັງເມື່ອຖືກຮ້ອງຂໍໄດ້."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ອ່ານ/ຂຽນ ໃສ່ຊັບພະຍາກອນທີ່ເປັນຂອງກຸ່ມວິໄຈ"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນອ່ານ ແລະຂຽນ ໃສ່ທຸກຊັບພະຍາກອນທີ່ເປັນຂອງກຸ່ມວິນິໄສ; ຕົວຢ່າງ: ໄຟລ໌ໃນ /dev. ສິ່ງນີ້ອາດສົ່ງຜົນກະທົບຕໍ່ຄວາມສະຖຽນ ແລະຄວາມປອດໄພຂອງລະບົບ. ສິ່ງນີ້ຄວນໃຊ້ສຳຫຼັບການວິເຄາະບັນຫາຈຳເພາະ ຂອງບາງຮາດແວໂດຍຜູ່ຜະລິດ ຫຼືຜູ່ປະຕິບັດການເທົ່ານັ້ນ."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ເປີດ ຫຼືປິດນຳໃຊ້ອົງປະກອບຂອງແອັບຯ"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"ອະນຸຍາດໃຫ້ແອັບຯບັນທຶກ ແລະປ່ຽນເສັ້ນທາງການປ້ອນຂໍ້ມູນອອກຂອງສຽງ."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"ການກວດຫາ Hotword"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"ອະນຸຍາດໃຫ້ແອັບຯຈັບຂໍ້ມູນສຽງສຳລັບການກວດຈັບ Hotword. ການຈັບຂໍ້ມູນສາມາດເກີດຂຶ້ນໃນພື້ນຫຼັງໄດ້ ແຕ່ຈະບໍ່ໄປຂັດຂວາງການຈັບຂໍ້ມູນສຽງອື່ນໆ (ເຊັ່ນ: ກ້ອງວິດີໂອ)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"ເສັ້ນທາງສຽງ"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມເສັ້ນທາງສຽງ ແລະປ່ຽນແປງການຕັດສິນໃຈນະໂຍບາຍສຽງໄດ້."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"ບັນທຶກວິດີໂອອອກ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"ອະນຸຍາດໃຫ້ແອັບຯບັນທຶກ ແລະປ່ຽນເສັ້ນທາງການປ້ອນຂໍ້ມູນອອກຂອງວິດີໂອ."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ບັນທຶກວິດີໂອອອກຢ່າງປອດໄພ"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນສາມາດຄວບຄຸມຄີກາດໄດ້."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"ຕິດຕາມການປ່ຽນແປງສະຖານະການເຊື່ອຖືກ."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນຕິດຕາມການປ່ຽນແປງໃນສະຖານະການເຊື່ອຖື."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"ລະບຸເອເຈນທີ່ເຊື່ອຖືໄດ້."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນລະບຸເອເຈນທີ່ເຊື່ອຖືໄດ້."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"ເປີດເມນູການຕັ້ງຄ່າເອເຈັນທີ່ເຊື່ອຖືໄດ້."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນເປີດການເຄື່ອນໄຫວທີ່ປ່ຽນແປງພຶດຕິກຳຂອງເອເຈັນທີ່ເຊື່ອຖືໄດ້."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ເຊື່ອມໂຍງຫາບໍລິການຕົວແທນການເຊື່ອຖື"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນເຊື່ອມໂຍງກັບບໍລິການຕົວແທນທີ່ເຊື່ອຖືໄດ້."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"ຕິດຕໍ່ກັບລະບົບອັບເດດ ແລະລະບົບກູ້ຂໍ້ມູນ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 50d8239..be7e571 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
<string name="android_system_label" msgid="6577375335728551336">"„Android“ sistema"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Asmeninė"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Darbo"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Asmeninės programos"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"„Android“ (darbas)"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Paslaugos, už kurias mokėjote"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Atlikite mokamus veiksmus."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Jūsų pranešimai"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Leidžiama savininką susaistyti su aukščiausio lygio darbalaukio fono sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"susaistyti su sąveikos balsu priemone"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Turėtojui leidžiama susaistyti programą su sąveikos balsu paslaugos aukščiausio lygio sąsaja. Įprastoms programoms to niekada neturėtų prireikti."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"tvarkyti pagrindines balso frazes"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Savininkui leidžiama tvarkyti pagrindines aktyvinamiesiems žodžiams aptikti skirtas frazes. To niekada neturėtų prireikti naudojant įprastas programas."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"susisaistyti su nuotoliniu ekranu"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Leidžiama savininkui susisaistyti su aukščiausiojo lygio nuotolinio ekrano sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"susaistyti su valdiklio paslauga"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Leidžiama programai naudoti bet kurį įdiegtą medijos dekoderį norint iššifruoti atkūrimą."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"tvarkyti patikimus prisijungimo duomenis"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Programoje galima įdiegti ir iš jos pašalinti CA sertifikatus kaip patikimus prisijungimo duomenis."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"paleisti programą, kai įrenginys yra neaktyvus"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Šiuo leidimu sistemai „Android“ leidžiama fone paleisti programą, kai įrenginys yra nenaudojamas."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"vykdyti suplanuotą programos darbą fone"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Šiuo leidimu sistemai „Android“ leidžiama fone vykdyti programą, kai to prašoma."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"skaityti / rašyti ištekliuose, priklausančiuose diagnostikai"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Leidžiama programai skaityti ir rašyti visuose diagnostikos grupei priklausančiuose ištekliuose, pvz., failuose, esančiuose /dev. Tai gali paveikti sistemos stabilumą ir saugą. Tai turėtų būti naudojama TIK gamintojui ar operatoriui atliekant aparatinės įrangos diagnostiką."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"įgalinti programos komponentus arba jų neleisti"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Programai leidžiama fiksuoti ir peradresuoti garso išvestį."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Aktyvinamųjų žodžių aptikimas"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Programai leidžiama įrašyti garsą, kad būtų galima aptikti aktyvinamuosius žodžius. Įrašymas gali būti vykdomas fone, bet tai netrikdo kitų garso įrašymo veiksmų (pvz., įrašymo vaizdo kamera)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Garso nukreipimas"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Programai leidžiama tiesiogiai valdyti garso nukreipimo ir garso nepaisymo politikos sprendimus."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"fiksuoti vaizdo išvestį"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Programai leidžiama fiksuoti ir peradresuoti vaizdo išvestį."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"fiksuoti saugią vaizdo išvestį"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Programai leidžiama valdyti „KeyGuard“."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Atsižvelgti į patikimos būsenos pakeitimus."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Programai leidžiama atsižvelgti į patikimos būsenos pakeitimus."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Teikti patikimos priemonės paslaugą."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Programai leidžiama teikti patikimos priemonės paslaugą."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Paleisti patikimo atstovo nustatymų meniu."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Leidžiama programai paleisti veiklą, keičiančią patikimo atstovo elgseną."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Susisaistyti su „trust agent“ paslauga"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Programai leidžiama susisaistyti su „trust agent“ paslauga."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Sąveikauti su naujiniu ir atkūrimo sistema"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5034464..b421da4 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"Pārsniedz"</string>
<string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistēma"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personisks"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Darba"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Personīgās lietotnes"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android darbs"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Maksas pakalpojumi"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Veikt darbības, par kurām, iespējams, būs jāmaksā."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Jūsu ziņojumi"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ļauj īpašniekam piesaistīt tapetes augstākā līmeņa lietotāja saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"Saistīšana ar balss mijiedarbības elementu"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Ļauj īpašniekam izveidot savienojumu ar balss mijiedarbības pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"pārvaldīt balss atslēgas frāzes"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Ļauj īpašniekam pārvaldīt atslēgas frāzes balss īsinājumvārdu identificēšanai. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Saites izveide ar attālu displeju"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ļauj īpašniekam izveidot saiti ar attāla displeja augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"saistīt ar logrīka pakalpojumu"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ļauj lietotnei izmantot jebkuru instalētu multivides failu dekodētāju, lai dekodētu failus atskaņošanai."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Uzticamo akreditācijas datu pārvaldība"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ļauj lietotnei instalēt un atinstalēt CA sertifikātus kā uzticamus akreditācijas datus."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"Lietojumprogrammas darbība dīkstāves laikā"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ar šo atļauju Android sistēmā lietojumprogramma darbojas fonā, kad ierīce netiek lietota."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"iespējot lietojumprogrammas plānoto darbību fonā"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Ar šo atļauju Android sistēmā lietojumprogramma pēc pieprasījuma darbojas fonā."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lasīt grupas “diag” resursus un rakstīt tajos"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Ļauj lietotnei lasīt un rakstīt jebkurā resursā, kas pieder diagnostikas grupai, piemēram, failiem mapē /dev. Tas var ietekmēt sistēmas stabilitāti un drošību. Var izmantot ražotājs vai operators TIKAI konkrētas aparatūras diagnostikai."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"iespējot vai atspējot lietotnes komponentus"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Ļauj lietotnei tvert un novirzīt audio izvadi."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Īsinājumvārda noteikšana"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Ļauj lietotnei tvert audio īsinājumvārda noteikšanai. Tveršana var notikt fonā, taču tā neaizkavē citu audio (piemēram, videokameras audio) tveršanu."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Audio maršrutēšana"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Ļauj lietotnei tieši kontrolēt audio maršrutēšanu un ignorēt audio politikas."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"tvert video izvadi"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Ļauj lietotnei tvert un novirzīt video izvadi."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"tvert drošu video izvadi"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Ļauj lietojumprogrammai pārvaldīt krātuvi."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Klausīties uzticamības statusa izmaiņas"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Ļauj lietojumprogrammai klausīties uzticamības statusa izmaiņas."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Nodrošināt uzticamības pārbaudes programmu"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Ļauj lietojumprogrammai nodrošināt uzticamības pārbaudes programmu."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Palaist uzticamības pārbaudes programmas iestatījumu izvēlni."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Ļauj lietojumprogrammai palaist darbību, kas maina uzticamības pārbaudes programmas rīcību."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Izveidot savienojumu ar uzticamības pārbaudes pakalpojumu"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ļauj lietojumprogrammai izveidot savienojumu ar uzticamības pārbaudes pakalpojumu."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Mijiedarbošanās ar atjauninājumu un atkopšanas sistēmu"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 1177284..803128f 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Андройд систем"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Хувийн"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Ажил"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Хувийн апп-ууд"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Андройд Ажил"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Танаас төлбөр авдаг үйлчилгээнүүд"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Таны төлбөрт оруулах зүйлийг хийх."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Таны мессеж"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Эзэмшигч нь ханын зурагны дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-уудад шаардлагагүй."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"дуугаар харьцагчтай холбох"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Эзэмшигчид дуугаар харьцах үйлчилгээний дээд-түвшний интерфейстэй холбох боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"дууны гол хэллэгүүдийг удирдах"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Эзэмшигчид дууны хотворд-г таних гол хэллэгүүдийг удирдах боломж олгоно. Энгийн апп-д хэзээ ч ашиглагдахгүй."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"алсын дэлгэцтэй холбогдох"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Эзэмшигчид алсын дэлгэц дэх дээд давхаргын интерфэйстэй холбогдох боломж олгоно. Энгийн апп-д шаардагдахгүй."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"виджет үйлчилгээтэй холбох"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Апп нь тоглуулах үедээ код тайлахдаа суулгагдсан ямарч медиа код тайлагчийг ашиглах боломжтой."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"итгэмжлэгдсэн жуухуудыг удирдах"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Апп-д CA сертификатуудыг итгэмжлэгдсэн жуух байдлаар суулгах болон устгахыг зөвшөөрнө."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"Сул зогсолтын хугацаанд аппликешнийг ажиллуулна"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Энэ зөвшөөрөл нь Андройд системд төхөөрөмжийг ашиглахгүй байгаа үед аппликешныг далд ажиллуулах боломж олгоно."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"аппликешны төлөвлөгдсөн далд ажлыг эхлүүлэх"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Энэ зөвшөөрөл нь Андройд системд төхөөрөмжийг хүсэлт гаргасан үед аппликешныг далд ажиллуулах боломж олгоно."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"оношлох грүпийн эзэмшдэг нөөцрүү унших/бичих"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Апп нь оношлох грүпийн эзэмшдэг, жишээ нь /dev доторх файлууд, дурын нөөцийг унших бичих боломжтой.Энэ нь системийн тогвортой байдал болон аюулгүй байдалд бодитоор нөлөөлнө. Энэ нь үйлдвэрлэгч болон операторын хардверт-зориулсан оношлогоонд ашиглагдана."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"апп компонентыг идэвхжүүлэх эсвэл идэвхгүй болгох"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Апп-т аудио гаралтыг барих, дахин чиглүүлэхийг зөвшөөрнө."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Хотворд таних"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Апп-д Хотворд илрүүлэхийн тулд аудиог бичихийг зөвшөөрнө. Бичилт далд хийгдэх бөгөөд бусад аудио бичилтэд (жнь. видео бичлэг) саад болохгүй."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Аудио чиглүүлэлт"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Апп-д аудио чиглүүлэгчийг шууд удирдах, аудио бодлогын шийдвэрүүдийг давах боломж олгоно."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"видео гаралтыг барих"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Апп-т видео гаралтыг барих, дахин чиглүүлэхийг зөвшөөрнө."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"найдвартай видео гаралтыг барих"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Аппликешн нь түлхүүр хамгаалагчыг удирдах боломжтой."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Итгэмжлэлд орж буй өөрчлөлтийг мэдэх."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Итгэмжлэлд орж буй өөрчлөлтийг мэдэх боломжийг аппликешнд олгоно."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Итгэмжлэгдсэн төлөөлөгч нийлүүлэх"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Аппликешнд итгэмжлэгдсэн төлөөлөгч нийлүүлэх боломж олгоно."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Итгэмжлэгдсэн агентын тохиргоо цэсийг эхлүүлэх."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Аппликешнд итгэмжлэгдсэн агентын авирыг өөрчлөх боломжтой үйлдлийг эхлүүлэхийг зөвшөөрнө."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Итгэмжлэгдсэн төлөөлөгчийн үйлчилгээтэй холбогдох"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Аппликешнд итгэмжлэгдсэн төлөөлөгчтэй холбогдох боломж олгоно."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Шинэчлэлт болон сэргээх системтэй харилцах"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 16c009e..1d1a75b 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -188,8 +188,9 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Peribadi"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Tempat Kerja"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Apl peribadi"</string>
+ <!-- no translation found for managed_profile_label (4287077106125758391) -->
+ <skip />
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Perkhidmatan yang anda perlu bayar"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Melakukan perkara yang boleh mengenakan bayaran kepada anda."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Mesej anda"</string>
@@ -400,6 +401,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi kertas dinding. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"terikat kepada interaksi suara"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan interaksi suara. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"urus frasa kunci suara"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Membenarkan pemegang menguruskan frasa kunci untuk pengesahan sebutan laluan. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"terikat kepada paparan jauh"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi paparan jauh. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"terikat kepada perkhidmatan widget"</string>
@@ -445,8 +448,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Membenarkan apl untuk menggunakan sebarang penyahkod media yang dipasangkan untuk menyahkod main semula."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"urus bukti kelayakan yang dipercayai"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Membenarkan apl memasang dan menyahpasang sijil CA sebagai bukti kelayakan yang dipercayai."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"jalankan aplikasi pada masa melahu"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Kebenaran ini membolehkan sistem Android menjalankan aplikasi di latar belakang semasa peranti tidak digunakan."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"jalankan kerja latar belakang dijadualkan aplikasi"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Kebenaran ini membolehkan sistem Android menjalankan aplikasi di latar belakang apabila diminta."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"baca/tulis ke sumber yang dimiliki oleh diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Membenarkan apl membaca dan menulis ke sebarang sumber yang dimiliki oleh kumpulan diag; contohnya, fail dalam /dev. Hal ini berpotensi menjejaskan kestabilan dan keselamatan sistem. Perkara ini seharusnya HANYA digunakan untuk diagnosis khusus perkakasan oleh pengilang atau pengendali."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"dayakan atau lumpuhkan komponen apl"</string>
@@ -520,6 +523,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Membenarkan apl menangkap dan mengubah hala output audio."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Pengesanan sebutan laluan"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Benarkan apl merakam audio untuk pengesahan Sebutan Laluan. Rakaman ini boleh berlaku di latar belakang tetapi tidak menghalang rakaman audio lain (cth. Kamkorder)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Penghalaan Audio"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Membenarkan apl untuk mengawal penghalaan audio secara langsung dan melangkau keputusan dasar audio."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"tangkap output video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Membenarkan apl menangkap dan mengubah hala output video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"tangkap output video selamat"</string>
@@ -1356,6 +1361,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Membenarkan aplikasi untuk mengawal pengawal kekunci."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Dengar perubahan keadaan amanah."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Membenarkan aplikasi mendengar perubahan dalam keadaan amanah."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Sediakan ejen amanah."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Membenarkan aplikasi menyediakan ejen amanah."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Mengikat kepada perkhidmatan ejen amanah"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Membenarkan aplikasi terikat kepada perkhidmatan ejen amanah."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Berinteraksi dengan kemas kini dan sistem pemulihan"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index acc4417..31fa11d 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personlig"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Jobb"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Personlige apper"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Betaltjenester"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Gjøre ting som kan koste deg penger."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Meldinger"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lar innehaveren binde det øverste nivået av grensesnittet til en bakgrunn. Skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"binde seg til en tjeneste for talehandlinger"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Gir innehaveren tillatelse til å binde til toppnivået av brukergrensesnittet for en tjeneste for talehandlinger. Dette skal ikke være nødvendig for vanlige apper."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"administrer nøkkelfraser for stemmebruk"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Tillater innehaveren å administrere nøkkelfraser for gjenkjennelse av talekommandoord. Skal aldri være nødvendig for normale apper."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"binde til ekstern skjerm"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lar innehaveren binde seg til det øverste grensesnittnivået for ekstern skjerm. Skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"binde til modultjenste"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Lar appen bruke en hvilken som helst installert mediedekoder for å dekode for avspilling."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrer pålitelig legitimasjon"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lar appen installere og avinstallere CA-sertifikater som pålitelig legitimasjon."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"kjør appen når den ikke er i bruk"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Denne tillatelsen gjør at Android-systemet kan kjøre appen i bakgrunnen mens enheten ikke er i bruk."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"kjøre appens planlagte bakgrunnsprosesser"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Denne tillatelsen gjør at Android-systemet kan kjøre appen i bakgrunnen når det bes om det."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lese/skrive ressurser eid av diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Lar appen lese og skrive til alle ressurser som eies av gruppen «diag», som for eksempel filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør BARE brukes av produsenten eller operatøren til maskinvarespesifikk diagnostikk."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivere eller deaktivere appkomponenter"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Lar appen ta opp og omdirigere lydutdata."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Gjenkjennelse av kommandoord"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Gir appen tillatelse til å ta opp lyd for å gjenkjenne kommandoord. Opptaket kan skje i bakgrunnen, men forhindrer ikke lydopptak i andre funksjoner (f.eks. i videoopptak)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Lydruting"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Tillater appen å styre lydruting direkte og overstyre angitte lydinnstillinger."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"ta opp fra videoutdata"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Lar appen ta opp og omdirigere videoutdata."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"ta opp fra sikre videoutdata"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Tillater at en app kontrollerer tastelåsen."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Oppdag endringer i tillitsstatusen."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Gir appen tillatelse til å oppdage endringer i tillitsstatusen."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Angivelse av en pålitelig agent."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Tillater appen å angi en pålitelig agent."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Start innstillingsmenyen til tillitsagenten."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Tillater apper å starte en aktivitet som endrer atferden til tillitsagenter."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Tilknytt en tillitsagent-tjeneste."</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Gir appen tillatelse til å knyttes til en tillitsagent-tjeneste."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Samhandling med oppdateringer og gjenopprettingssystem"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d973812..a655f36 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
<string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Persoonlijk"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Werk"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Persoonlijke apps"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android werk"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Services waarvoor u moet betalen"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Activiteiten uitvoeren waarvoor kosten in rekening kunnen worden gebracht."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Uw berichten"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Hiermee wordt de houder toegestaan zich te verbinden met de hoofdinterface van een achtergrond. Nooit vereist voor normale apps."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"binden aan een service voor spraakinteractie"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Hiermee kan de houder binden aan de hoofdinterface van een service voor spraakinteractie. Nooit vereist voor normale apps."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gesproken trefwoorden beheren"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Hiermee kan de houder de trefwoorden voor gesproken hotword-detectie beheren. Nooit vereist voor normale apps."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"verbinding maken met een extern display"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een extern display. Nooit vereist voor normale apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"verbinden met een widgetservice"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Hiermee kan de app alle geïnstalleerde mediadecoders gebruiken om te decoderen voor het afspelen."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"vertrouwde inloggegevens beheren"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Hiermee kan de app CA-certificaten installeren en verwijderen als vertrouwde inloggegevens."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"app uitvoeren tijdens inactiviteit"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Met dit recht kan het Android-systeem de app op de achtergrond uitvoeren terwijl het apparaat niet wordt gebruikt."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"geplande achtergrondwerkzaamheden van de app uitvoeren"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Met dit recht kan het Android-systeem de app op de achtergrond uitvoeren wanneer dit wordt gevraagd."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lezen/schrijven naar bronnen van diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Hiermee kan de app lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of provider."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"componenten van apps in- of uitschakelen"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Hiermee kan de app audio-uitvoer vastleggen en verwerken."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detectie van hotwords"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Hiermee kan de app audio opnemen voor het detecteren van hotwords. Het opnemen kan op de achtergrond plaatsvinden, maar voorkomt niet dat andere audio wordt opgenomen (bijvoorbeeld in Camcorder)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Audioroutering"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Hiermee kan de app rechtstreeks audioroutering beheren en audiobeleid negeren."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"video-uitvoer vastleggen"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Hiermee kan de app video-uitvoer vastleggen en verwerken."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"beveiligde video-uitvoer vastleggen"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Staat toe dat een app de toetsbeveiliging beheert."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Controleren op wijzigingen in de trust-status."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Toestaan dat een app controleert op wijzigingen in de trust-status."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Een trust-agent aanleveren."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Hiermee kan een app een trust-agent aanleveren."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Menu met instellingen voor vertrouwensagent starten."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Hiermee kan een app een activiteit starten waarmee het gedrag van de vertrouwensagent wordt gewijzigd."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Binden aan een trust-agentservice"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Toestaan dat een app wordt gebonden aan een trust-agentservice."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interactie met update- en herstelsysteem"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index b452018..c30ad74 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
<string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Osobiste"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Praca"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Aplikacje osobiste"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android w pracy"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Usługi płatne"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Wykonywanie czynności, za które pobierana jest opłata."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Twoje wiadomości"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu tapety. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"powiąż z interaktorem głosowym"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi interakcji głosowej. Nieprzeznaczone dla zwykłych aplikacji."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"zarządzanie frazami głosowymi"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Pozwala zarządzać frazami używanymi do wykrywania słów-kluczy w komendach głosowych. Nie powinno być nigdy potrzebne w zwykłych aplikacjach."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"powiązanie z wyświetlaczem zdalnym"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu wyświetlacza zdalnego. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"powiązanie z usługą widżetów"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Pozwala aplikacji na użycie dowolnego zainstalowanego dekodera multimediów do odtwarzania."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"zarządzanie zaufanymi danymi uwierzytelniającymi"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Zezwala aplikacji na instalowanie i odinstalowywanie certyfikatów CA jako zaufanych danych uwierzytelniających."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"uruchom aplikację w czasie bezczynności"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To uprawnienie pozwala systemowi Android uruchomić aplikację w tle, gdy urządzenie nie jest używane."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"uruchom zaplanowane działania aplikacji w tle"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"To uprawnienie zezwala Androidowi na uruchamianie aplikacji w tle na jej żądanie."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"czytanie/zapisywanie w zasobach należących do diagnostyki"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Pozwala aplikacji na czytanie i zapisywanie wszystkich zasobów należących do grupy diagnostyki, na przykład plików w katalogu /dev. Może to potencjalnie wpłynąć na stabilność i bezpieczeństwo systemu. Powinno być wykorzystywane WYŁĄCZNIE do diagnozowania sprzętu przez producenta lub operatora."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"włączanie lub wyłączanie składników aplikacji"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Zezwala aplikacji na przechwytywanie i przekierowywanie wyjścia audio."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Wykrywanie słów-kluczy"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Umożliwia aplikacji przechwytywanie dźwięku w celu wykrywania słów-kluczy. Może się to odbywać w tle i nie uniemożliwia innego przechwytywania dźwięku (np. z kamery)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Kierowanie dźwiękowe"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Zezwala aplikacji na bezpośrednie sterowanie kierowaniem dźwiękowym i zastępowanie decyzji zasad dźwięku."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"przechwyć wyjście wideo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Zezwala aplikacji na przechwytywanie i przekierowywanie wyjścia wideo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"przechwyć bezpieczne wyjście wideo"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Umożliwia aplikacji kontrolowanie zabezpieczenia kluczami."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Monitoruj zmiany w stanie zaufania."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Zezwala aplikacji na monitorowanie zmian w stanie zaufania."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Dostarczaj agenta zaufania."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Zezwala aplikacji na dostarczanie agenta zaufania."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Uruchom menu ustawień zaufanego agenta."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Umożliwia aplikacji uruchamianie czynności, która zmienia działanie zaufanego agenta."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Powiąż z usługą agenta zaufania"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Zezwala aplikacji na powiązanie z usługą agenta zaufania."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interakcja z systemem odzyskiwania i aktualizacjami"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index d3f5a63..2e4e423 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Aplicações pessoais"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Trabalho Android"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Serviços que implicam pagamento"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Efetuar ações que implicam pagamento."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"As suas mensagens"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite ao titular vincular-se à interface de nível superior de uma imagem de fundo. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"vincular a um interlocutor de voz"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite que o titular vincule a interface de nível superior de um serviço de interação de voz. Nunca deverá ser necessário para aplicações normais."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gerir expressões-chave de voz"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permite ao proprietário gerir as expressões-chave para a deteção de palavras de ativação de voz. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"associar a um ecrã remoto"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite ao detentor associar a interface de nível superior a um ecrã remoto. Nunca deve ser necessário para aplicações normais."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a um serviço de widget"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que a aplicação utilize qualquer descodificador de multimédia instalado para descodificar a reprodução."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gerir credenciais fidedignas"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que a aplicação instale e desinstale certificados da AC (Autoridade de certificação) como credenciais fidedignas."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"executar aplicação durante o tempo de inatividade"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Esta autorização permite ao sistema Android executar a aplicação em segundo plano enquanto o dispositivo não estiver a ser utilizado."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"executar o trabalho em segundo plano da aplicação"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Esta autorização permite ao sistema Android executar a aplicação em segundo plano quando solicitado."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ler/escrever em recursos propriedade de diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite à aplicação ler e escrever em qualquer recurso que seja propriedade do grupo diag; por exemplo, ficheiros em /dev. Isto pode potencialmente afetar a estabilidade e a segurança do sistema e deve ser utilizado APENAS para diagnósticos específicos do hardware pelo fabricante ou pelo operador."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ativar ou desativar componentes da aplicação"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite à aplicação capturar e redirecionar a saída de áudio."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Deteção de palavra de ativação"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permite à aplicação capturar áudio para deteção da palavra de ativação. A captura pode acontecer em segundo plano, mas não impede outras capturas de áudio (por exemplo com câmara de vídeo)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Direcionamento do áudio"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Permite que a aplicação controle diretamente o direcionamento do áudio e substitua as decisões da política de áudio."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capturar saída de vídeo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite à aplicação capturar e redirecionar a saída de vídeo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capturar saída de vídeo segura"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que uma aplicação controle a proteção de teclado."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Registar alterações no estado trust."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que uma aplicação registe alterações no trust state."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Fornecer um agente fidedigno."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite que uma aplicação forneça um agente fidedigno."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Vincular a um serviço de trust agent"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que uma aplicação fique vinculada a um serviço de trust agent."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagir com o sistema de recuperação e de atualização"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ae15d48..3df7ecb 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Aplicativos pessoais"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android para trabalho"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Serviços que geram gastos"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Faça coisas que podem custar dinheiro."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Suas mensagens"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite que o proprietário utilize interface de nível superior de um plano de fundo. Nunca deve ser necessário para aplicativos normais."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"associar a um interagente de voz"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite que o proprietário use a interface de nível superior de um serviço de interação de voz. Não deve ser necessário para aplicativos comuns."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gerenciar frases-chave de voz"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permite ao titular gerenciar as frases-chave para detecção de hotword por voz. Isso nunca será necessário para aplicativos normais."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"usar uma tela remota"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite que o proprietário use a interface de nível superior de uma tela remota. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sujeitar-se a um serviço de widget"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que o aplicativo use qualquer decodificador de mídia instalado para reprodução."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gerenciar credenciais confiáveis"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que o aplicativo instale e desinstale certificados CA como credenciais confiáveis."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"executar o aplicativo durante o tempo ocioso"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Permite que o sistema Android execute o aplicativo em segundo plano enquanto o dispositivo não está em uso."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"executar as operações programadas do aplicativo em segundo plano"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Esta permissão permite ao sistema Android executar o aplicativo em segundo plano quando solicitado."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ler/gravar em recursos pertencentes ao diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que um aplicativo leia e grave em qualquer recurso que pertença ao grupo de diagnósticos, por exemplo, arquivos in/dev. Isso pode afetar a estabilidade e a segurança do sistema. Esse recurso deve ser usado APENAS para diagnósticos específicos do hardware realizados pelo fabricante ou pela operadora."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ativar ou desativar os componentes do aplicativo"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite que o aplicativo capture e redirecione a saída de áudio."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Detecção de hotwords"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Permite que o dispositivo capture áudio para a detecção de hotwords. A captura pode acontecer em segundo plano, mas não impede outras capturas de áudio (como por uma câmera de vídeo)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Roteamento de áudio"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Permite que o app controle diretamente o roteamento de áudio e substitua as decisões relacionadas a políticas de áudio."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"capturar saída de vídeo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite que o aplicativo capture e redirecione a saída de vídeo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"capturar saída de vídeo segura"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite que o aplicativo controle o bloqueio de teclado."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Detectar alterações no estado de confiança."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite que o aplicativo detecte alterações no estado de confiança."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Fornecer um agente de confiança."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite que um aplicativo forneça um agente de confiança."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Associar a um serviço de agente de confiança"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite que o aplicativo se associe a um serviço de agente de confiança."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagir com o sistema de atualizações e recuperação"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index a3cf563..ff26d8f 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -246,9 +246,9 @@
<skip />
<string name="safeMode" msgid="2788228061547930246">"Modus segirà"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
- <!-- no translation found for user_owner_label (2804351898001038951) -->
+ <!-- no translation found for user_owner_label (6465364741001216388) -->
<skip />
- <!-- no translation found for managed_profile_label (6260850669674791528) -->
+ <!-- no translation found for managed_profile_label (4287077106125758391) -->
<skip />
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servetschs che custan"</string>
<!-- no translation found for permgroupdesc_costMoney (3293301903409869495) -->
@@ -634,6 +634,10 @@
<skip />
<!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) -->
<skip />
+ <!-- no translation found for permlab_manageVoiceKeyphrases (1252285102392793548) -->
+ <skip />
+ <!-- no translation found for permdesc_manageVoiceKeyphrases (8476560722907530008) -->
+ <skip />
<!-- no translation found for permlab_bindRemoteDisplay (1782923938029941960) -->
<skip />
<!-- no translation found for permdesc_bindRemoteDisplay (1261242718727295981) -->
@@ -722,9 +726,9 @@
<skip />
<!-- no translation found for permdesc_manageCaCertificates (4015644047196937014) -->
<skip />
- <!-- no translation found for permlab_bindIdleService (816311765497613780) -->
+ <!-- no translation found for permlab_bindJobService (3637568367978271086) -->
<skip />
- <!-- no translation found for permdesc_bindIdleService (1767538493214100612) -->
+ <!-- no translation found for permdesc_bindJobService (3473288460524119838) -->
<skip />
<string name="permlab_diagnostic" msgid="8076743953908000342">"leger/scriver en resursas che appartegnan a diagnostics"</string>
<!-- no translation found for permdesc_diagnostic (6608295692002452283) -->
@@ -863,6 +867,10 @@
<skip />
<!-- no translation found for permdesc_captureAudioHotword (9151807958153056810) -->
<skip />
+ <!-- no translation found for permlab_modifyAudioRouting (7738060354490807723) -->
+ <skip />
+ <!-- no translation found for permdesc_modifyAudioRouting (7205731074267199735) -->
+ <skip />
<!-- no translation found for permlab_captureVideoOutput (2246828773589094023) -->
<skip />
<!-- no translation found for permdesc_captureVideoOutput (359481658034149860) -->
@@ -2178,6 +2186,14 @@
<skip />
<!-- no translation found for permdesc_trust_listener (8233895334214716864) -->
<skip />
+ <!-- no translation found for permlab_provide_trust_agent (5465587586091358316) -->
+ <skip />
+ <!-- no translation found for permdesc_provide_trust_agent (3865702641053068148) -->
+ <skip />
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<!-- no translation found for permlab_bind_trust_agent_service (8242093169457695334) -->
<skip />
<!-- no translation found for permdesc_bind_trust_agent_service (7041930026024507515) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 03b7d40..110b243 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -188,8 +188,9 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Serviciu"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Aplicații personale"</string>
+ <!-- no translation found for managed_profile_label (4287077106125758391) -->
+ <skip />
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servicii cu plată"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Efectuează acţiuni care sunt cu plată."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Mesajele dvs."</string>
@@ -400,6 +401,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unei imagini de fundal. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"conectare la un serviciu de interacțiune vocală"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de interacțiune vocală. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"gestionarea expresiilor cheie vocale"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Permite titularului să gestioneze expresiile cheie pentru detectarea expresiei de activare. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"conectare la un ecran la distanță"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite proprietarului să se conecteze la interfața de nivel superior a unui ecran la distanță. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"conectare la un serviciu widget"</string>
@@ -445,8 +448,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite aplicaţiei să utilizeze orice decodor media instalat pentru a decodifica redarea."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestionarea acreditărilor de încredere"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite aplicației să instaleze și să dezinstaleze certificate CA ca acreditări de încredere."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"rulează aplicația în timp ce dispozitivul este inactiv"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cu această permisiune, sistemul Android poate rula aplicația în fundal în timp ce dispozitivul nu este utilizat."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"rulează operațiile programate, în fundal, ale aplicației"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Cu această permisiune, sistemul Android poate rula aplicația în fundal la cerere."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"citire/scriere în resursele deţinute de diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite aplicaţiei să citească şi să scrie în orice resursă deţinută de grupul diag, de ex., fişierele din /dev. Această permisiune ar putea să afecteze stabilitatea şi securitatea sistemului. Permisiunea trebuie utilizată NUMAI de producător sau de operator pentru diagnostice specifice pentru hardware."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activare sau dezactivare a componentelor aplicaţiei"</string>
@@ -520,6 +523,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Permite aplicației să intercepteze și să redirecționeze ieșirea audio."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"detectarea expresiei de activare"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Activează captarea semnalului audio de către aplicație pentru detectarea expresiei de activare. Captarea poate avea loc în fundal, dar nu împiedică altă captare audio (de ex., cameră video)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Cale audio"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Permite aplicației să controleze în mod direct calea audio și să suprascrie deciziile privind politicile audio."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"să intercepteze ieșirea video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Permite aplicației să intercepteze și să redirecționeze ieșirea video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"să intercepteze ieșirea video securizată"</string>
@@ -1356,6 +1361,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Permite unei aplicații să controleze blocarea tastaturii."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Detectarea modificărilor în starea de încredere."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Permite unei aplicații să detecteze modificările în starea de încredere."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Indicați un agent de încredere."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Permite unei aplicații să indice un agent de încredere."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Asocierea la un serviciu „agenți de încredere”."</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Permite unei aplicații să se asocieze la un serviciu „agent de încredere”."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interacțiune cu sistemul de recuperare și de actualizare"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index bb98508..12d1895 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -176,7 +176,7 @@
<string name="global_action_lock" msgid="2844945191792119712">"Блокировка экрана"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Отключить питание"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Отчет об ошибке"</string>
- <string name="bugreport_title" msgid="2667494803742548533">"Создание отчета об ошибке"</string>
+ <string name="bugreport_title" msgid="2667494803742548533">"Отчет об ошибке"</string>
<string name="bugreport_message" msgid="398447048750350456">"Информация о текущем состоянии вашего устройства будет собрана и отправлена по электронной почте. Подготовка отчета займет некоторое время."</string>
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Режим без звука"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Выключить"</string>
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Личные данные"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Работа"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Персональные приложения"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android для бизнеса"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Платные услуги"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Приложение сможет использовать платные услуги."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Сообщения"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Приложение сможет подключаться к базовому интерфейсу службы обоев. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"Подключение к службам голосового взаимодействия"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Приложение сможет подключаться к базовому интерфейсу служб голосового взаимодействия. Это разрешение обычно используется только специальными приложениями."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"Управление ключевыми фразами для распознавания голосовых команд"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Управление ключевыми фразами для функции распознавания голосовых команд. Это разрешение обычно используется только специальными приложениями."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Подключение к удаленному дисплею"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Приложение сможет подключаться к базовому интерфейсу удаленного дисплея. Это разрешение обычно используется только специальными приложениями."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"Подключение к службе виджетов"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Приложение сможет использовать любой установленный дешифратор."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Управление учетными данными"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Приложение сможет устанавливать сертификаты ЦС в качестве надежных учетных данных, а также удалять их."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"выполнение приложения в спящем режиме"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Система Android сможет выполнять приложение в фоновом режиме, когда устройство не используется."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"Запуск приложения в фоновом режиме по расписанию"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Запуск приложения в фоновом режиме по запросу."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"Чтение/запись данных в системы диагностики"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Приложение сможет считывать и записывать данные системы диагностики (например, файлы в каталоге /dev). Это может повлиять на стабильность и безопасность системы. Это разрешение должно использоваться ТОЛЬКО производителем или оператором для диагностики аппаратного обеспечения."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"Включение/отключение компонентов приложения"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Приложение сможет захватывать и перенаправлять аудиосигнал."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"распознавать голосовые команды"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Приложение сможет анализировать звук для распознавания голосовых команд. Этот процесс выполняется в фоновом режиме и не мешает другим операциям (например, записи видеоролика)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Маршрутизация аудио"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Управление маршрутизацией аудио и перезапись правил, связанных с аудио."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"захват видеосигнала"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Приложение сможет захватывать и перенаправлять видеосигнал."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"захват защищенного видеосигнала"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Приложение сможет управлять хранилищем ключей."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Отслеживание изменений статуса доверия"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Приложение сможет отслеживать изменения в статусе доверия."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Доверенный агент"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Предоставление доверенных агентов."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Запуск настроек Trust Agent"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Запуск меню, позволяющего управлять настройками Trust Agent."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Подключение к службе Trust Agents"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Приложение сможет подключаться к службе Trust Agents."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Взаимодействовать с системой восстановления и обновлениями"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 7e8019a..ab596c5 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Osobné"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Práca"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Osobné aplikácie"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android na prácu"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Spoplatnené služby"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Vykonávanie činností, ktoré vás môžu stáť peniaze."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vaše správy"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania tapety. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"viazanie na hlasovú interakciu"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby hlasovej interakcie. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"správa vyslovených kľúčových fráz"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Umožňuje držiteľovi spravovať kľúčové frázy pre rozpoznávanie vyslovených kľúčových slov. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"viazať na vzdialený displej"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania vzdialeného displeja. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"viazať sa k službe miniaplikácie"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Umožňuje aplikácii používať na reprodukciu ľubovoľný nainštalovaný dekódovač na dekódovanie."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"spravovať dôveryhodné poverenia"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Umožňuje aplikácii inštalovať a odinštalovať certifikáty CA ako dôveryhodné poverenia."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"spustiť aplikáciu počas nečinnosti"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Toto povolenie umožňuje systému Android spustiť aplikáciu na pozadí, keď sa zariadenie nepoužíva."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"spustenie naplánovanej práce aplikácie na pozadí"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Toto povolenie umožňuje systému Android spustiť na základe požiadavky aplikáciu na pozadí."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"čítanie alebo zápis do prostriedkov funkcie diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Umožňuje aplikácii čítať ľubovoľné prostriedky v skupine diag, napr. súbory v priečinku /dev, a zapisovať do nich. Môže dôjsť k ovplyvneniu stability a bezpečnosti systému. Toto nastavenie by mal používať IBA výrobca či operátor na diagnostiku hardvéru."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"povoliť alebo zakázať súčasti aplikácie"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Umožňuje aplikácii zachytiť a presmerovať výstup zvuku."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Rozpoznanie kľúčových slov"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Umožňuje aplikácii zaznamenať zvuk s cieľom rozpoznať kľúčové slová. Záznam sa môže uskutočniť na pozadí a nebráni inému zaznamenávaniu zvuku (napríklad videokamerou)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Smerovanie zvuku"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Umožňuje aplikácii priamo ovládať smerovanie zvuku a prepísať rozhodnutia týkajúce sa pravidiel pre zvuk."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"zachytiť výstup videa"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Umožňuje aplikácii zachytiť a presmerovať výstup videa."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"zachytiť zabezpečený výstup videa"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Umožňuje aplikácii ovládať technológiu keyguard."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Reagovanie na zmeny stavu dôveryhodnosti."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Umožňuje aplikácii reagovať na zmeny stavu dôveryhodnosti."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Poskytnúť dôveryhodného agenta"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Umožňuje aplikácii poskytnúť dôveryhodného agenta."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Spustenie ponuky nastavení dôveryhodného agenta"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Umožňuje aplikácii spustiť aktivitu, ktorá zmení správanie dôveryhodného agenta."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Viazanie sa na službu zástupcu dôveryhodnosti"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Umožňuje aplikácii viazať sa na službu zástupcu dôveryhodnosti."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interakcia so systémom aktualizácií a obnovenia"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index e681737..cc06fd3 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
<string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Osebno"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Služba"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Osebne aplikacije"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android – službeno"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Plačljive storitve"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Dovolite stvari, za katere bo morda treba plačati."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vaša sporočila"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Imetniku omogoča povezavo z vmesnikom ozadja najvišje ravni. Tega nikoli ni treba uporabiti za navadne programe."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"povezovanje z glasovnim interaktorjem"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Imetniku omogoča povezovanje z vmesnikom storitve glasovne interakcije najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"upravljanje glasovnih ključnih besednih zvez"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Imetniku omogoča upravljanje ključnih besednih zvez za zaznavanje sprožilne besede. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"povezava z oddaljenim prikazom"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Imetniku omogoča povezovanje z vmesnikom oddaljenega prikaza najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"poveži s storitvijo pripomočka"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Programu omogoča, da uporabi kateri koli dekodirnik večpredstavnosti za predvajanje."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"upravljanje preverjenih poverilnic"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Aplikaciji dovoli nameščanje in odstranjevanje potrdil overitelja potrdil kot preverjenih poverilnic."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"izvajanje aplikacije ob nedejavnosti"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To dovoljenje sistemu Android omogoča, da izvaja aplikacijo v ozadju, ko naprava ni v uporabi."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"izvajanje načrtovanega dela aplikacije v ozadju"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"To dovoljenje sistemu Android omogoča, da na zahtevo izvaja aplikacijo v ozadju."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"branje/pisanje v sredstva, ki so v lasti skupine za diagnostiko"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Programu omogoča branje in pisanje na poljuben vir, ki je v lasti skupine za diagnostiko; na primer datoteke v mapi /dev. To lahko vpliva na stabilnost in varnost sistema. To naj uporablja SAMO izdelovalec ali operater za diagnostiko, specifično za strojno opremo."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"omogočanje ali onemogočanje komponent programa"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Omogoči aplikaciji, da zajame in preusmeri avdioizhod."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Zaznavanje sprožilnih besed"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Aplikaciji dovoljuje snemanje zvoka za zaznavanje sprožilnih besed. Snemanje je možno tudi v ozadju, ne preprečuje pa drugega snemanja zvoka (npr. z videokamero)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Usmerjanje zvoka"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Aplikaciji dovoli neposredno nadziranje usmerjanja zvoka in preglasitev odločitev pravilnika za zvok."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"zajem videoizhoda"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Omogoči aplikaciji, da zajame in preusmeri videoizhod."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"zajem varnega videoizhoda"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Aplikaciji omogoča nadzor zaklepanja tipkovnice."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Spremljanje sprememb stanja zaupanja."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Aplikaciji dovoli spremljanje sprememb stanja zaupanja."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Navedba posrednika zaupanja."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Aplikaciji dovoli navesti posrednika zaupanja."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Odpri meni z nastavitvami posrednika zaupanja."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Dovoli aplikaciji zagon dejavnosti, ki spremeni način delovanja posrednika zaupanja."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Povezovanje s storitvijo posrednikov zaupanja"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Aplikaciji dovoli povezovanje s storitvijo posrednikov zaupanja."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Uporaba sistema za posodobitev in obnovitev"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 51a7839..099e6ef 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android систем"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Лично"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Посао"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Личне апликације"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android за посао"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Услуге које се плаћају"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Покреће радње које могу да се плаћају."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Поруке"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозвољава власнику да се повеже са интерфејсом позадине највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"повежи са гласовним интерактором"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа услуге гласовне интеракције. Не би требало никада да буде потребно за уобичајене апликације."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"управљање усменим кључним фразама"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Дозвољава власнику да управља кључним фразама за откривање усмених актуелних речи. Никада не би требало да буде потребно за уобичајене апликације."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"повезивање са удаљеним екраном"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозвољава власнику да се повеже са интерфејсом удаљеног екрана највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обавезивање на услугу виџета"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Омогућава апликацији да користи било који инсталирани декодер медија за декодирање за репродукцију."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"управљање поузданим акредитивима"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Дозвољава апликацији да инсталира и деинсталира CA сертификате као поуздане акредитиве."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"покреће апликације током неактивности"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ова дозвола омогућава систему Android да покреће апликације у позадини док се уређај не користи."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"покретање заказаних задатака апликације у позадини"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Ова дозвола омогућава систему Android да покреће апликацију у позадини на захтев."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"читање ресурса у власништву дијагностике и уписивање података у њих"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Дозвољава апликацији да чита и уписује податке у било који ресурс у власништву групе за дијагностиковање, на пример, датотеке у директоријуму /dev. То може да угрози стабилност и безбедност система и треба да је користе САМО произвођач или оператер у сврхе дијагностиковањa хардвера."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"омогућавање или онемогућавање компоненти апликације"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Дозвољава апликацији да снима и преусмерава аудио садржај."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Откривање актуелних речи"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Дозвољава апликацији да снима звук за откривање актуелних речи. Снимање може да се дешава у позадини, али не спречава друга снимања звука (нпр. камкордер)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Преусмеравање звука"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Дозвољава апликацији да директно контролише преусмеравање звука и замени одлуке смерница о звуку."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"снимање видео садржаја"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Дозвољава апликацији да снима и преусмерава видео садржај."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"снимање безбедног видео садржаја"</string>
@@ -608,7 +612,7 @@
<string name="permlab_setWallpaperHints" msgid="3278608165977736538">"прилагођавање величине позадине"</string>
<string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Дозвољава апликацији да подеси савете за системску величину позадине."</string>
<string name="permlab_masterClear" msgid="2315750423139697397">"поновно постављање фабричких подразумеваних подешавања"</string>
- <string name="permdesc_masterClear" msgid="3665380492633910226">"Дозвољава апликацији да поново постави комплетна фабричка подешавања система и тиме избрише све податке, конфигурацију и инсталиране апликације."</string>
+ <string name="permdesc_masterClear" msgid="3665380492633910226">"Дозвољава апликацији да ресетује систем на фабричка подешавања и тиме избрише све податке, конфигурацију и инсталиране апликације."</string>
<string name="permlab_setTime" msgid="2021614829591775646">"подешавање времена"</string>
<string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"Дозвољава апликацији да промени време на сату таблета."</string>
<string name="permdesc_setTime" product="default" msgid="1855702730738020">"Дозвољава апликацији да промени време на сату телефона."</string>
@@ -732,8 +736,8 @@
<string name="policylab_forceLock" msgid="2274085384704248431">"Закључавање екрана"</string>
<string name="policydesc_forceLock" msgid="1141797588403827138">"Контролишите начин и време закључавања екрана."</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Брисање свих података"</string>
- <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Брисање података на таблету без упозорења враћањем фабричких података."</string>
- <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Избришите податке на телефону без упозорења враћањем фабричких података."</string>
+ <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Брисање података на таблету без упозорења ресетовањем на фабричка подешавања."</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Избришите податке на телефону без упозорења ресетовањем на фабричка подешавања."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Подесите глобални прокси сервер уређаја"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Подесите глобални прокси сервер уређаја који ће се користити док су омогућене смернице. Само први администратор уређаја поставља ефективни глобални прокси сервер."</string>
<string name="policylab_expirePassword" msgid="885279151847254056">"Подешавање истека лозинке екрана"</string>
@@ -906,8 +910,8 @@
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%d</xliff:g> пута сте погрешно унели PIN. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%d</xliff:g> несупешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу података за пријављивање на Google.\n\n Покушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%d</xliff:g> несупешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу података за пријављивање на Google.\n\n Покушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Неправилно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%d</xliff:g> пута. Након још неуспешних покушаја (<xliff:g id="NUMBER_1">%d</xliff:g>) таблет ће бити враћен на подразумевана фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Неисправно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%d</xliff:g> пута. Након још неуспешних покушаја (<xliff:g id="NUMBER_1">%d</xliff:g>) телефон ће бити враћен на подразумевана фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Неправилно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%d</xliff:g> пута. Након још неуспешних покушаја (<xliff:g id="NUMBER_1">%d</xliff:g>) таблет ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Неисправно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%d</xliff:g> пута. Након још неуспешних покушаја (<xliff:g id="NUMBER_1">%d</xliff:g>) телефон ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Неисправно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Таблет ће сада бити враћен на подразумевана фабричка подешавања."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Неисправно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Телефон ће сада бити враћен на подразумевана фабричка подешавања."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Покушајте поново за <xliff:g id="NUMBER">%d</xliff:g> секунде(и)."</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Дозвољава апликацији да контролише заштиту шифром."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Праћење промена Trust стања."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Дозвољава апликацији да прати промене Trust стања."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Обезбеђивање поузданог агента."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Дозвољава апликацији да обезбеди поузданог агента."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Везивање за услугу Trust agents"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Дозвољава апликацији да се веже за услугу Trust agents."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Интеракција са системом за ажурирање и опоравак"</string>
@@ -1582,8 +1592,8 @@
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте PIN неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Унели сте лозинку неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Покушали сте да откључате таблет неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. Након још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја таблет ће бити враћен на подразумевана фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Покушали сте да откључате телефон неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја телефон ће бити враћен на подразумевана фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Покушали сте да откључате таблет неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. Након још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја таблет ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Покушали сте да откључате телефон неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја телефон ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Покушали сте да откључате таблет неисправно <xliff:g id="NUMBER">%d</xliff:g> пута. Таблет ће сада бити враћен на подразумевана фабричка подешавања."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Покушали сте да откључате телефон неисправно <xliff:g id="NUMBER">%d</xliff:g> пута. Телефон ће сада бити враћен на подразумевана фабричка подешавања."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 595dadd..46bb563 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personligt"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Arbetet"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Personliga appar"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android – arbete"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Tjänster som kostar pengar"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Göra saker som kan kosta pengar."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Dina meddelanden"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Innehavaren kan binda till den översta nivåns gränssnitt för en bakgrund. Ska inte behövas för vanliga appar."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bind till en röstkomponent"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en rösttjänst. Ska inte behövas för vanliga appar."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"hantera sökfraser för röstkommandon"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Innehavaren får hantera sökfraser för identifiering av röstkommandon. Detta ska inte behövas för vanliga appar."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind till en fjärrskärm"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en fjärrskärm. Ska inte behövas för vanliga appar."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind till en widget"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Tillåter att appen använder installerade medieavkodare för att avkoda media för uppspelning."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"hantera betrodda uppgifter"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Tillåter att appen installerar och avinstallerar CA-certifikat som betrodda uppgifter."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"kör appen när enheten är inaktiv"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Med den här behörigheten tillåts Android-systemet att köra appen i bakgrunden när enheten inte används."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"kör appens schemalagda bakgrundsarbete"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Med den här behörigheten får Android-systemet köra appen i bakgrunden när detta begärs."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"läsa/skriva till resurser som ägs av diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Tillåter att appen läser och skriver till en resurs som ägs av diag-gruppen, till exempel filer i /dev. Detta kan eventuellt påverka systemets stabilitet och säkerhet. Detta bör ENDAST användas av tillverkaren eller operatören för maskinvaruspecifik diagnostik."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivera eller inaktivera appkomponenter"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Tillåt att appen fångar upp och omdirigerar ljudutgången."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Kommandoordsidentifiering"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Tillåter att appen spelar in ljud för att upptäcka kommandoord. Inspelningen kan pågå i bakgrunden utan att hindra andra ljudinspelningar (t.ex. med videokamera)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Ljuddirigering"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Tillåter att appen styr ljuddirigeringen direkt och åsidosätter ljudpolicybeslut."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"fånga upp videoutgång"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Tillåt att appen fångar upp och omdirigerar videoutgången."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"fånga upp säker videoutgång"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Tillåter att en app kontrollerar knapplåsfunktionen."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Lyssna efter ändringar i betrodda agenters status."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Tillåter att en app lyssnar efter ändringar i den betrodda agentens status."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Tillhandahåll en betrodd agent."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Tillåter att en app tillhandahåller en betrodd agent."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bind till en tjänst från en betrodd agent"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Tillåter att en app binds vid en tjänst från en betrodd agent."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Interagera med uppdaterings- och återställningssystemet"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index bb39100..595c807 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
<string name="android_system_label" msgid="6577375335728551336">"Mfumo wa Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Binafsi"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Kazini"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Programu binafsi"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Kazi ya Android"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Huduma ambazo zinakugharimu pesa"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Fanya mambo ambayo yanaweza kukugharimu pesa."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Ujumbe wako"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Inaruhusu kishikiliaji kushurutisha kwa kusano ya kiwango cha juu cha mandhari. Haipaswi kamwe kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bandika kwenye mwingiliano wa sauti"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Humruhusu mmiliki kubandika kwenye kiolesura cha hali ya juu cha huduma ya muingiliano wa sauti. Isihitajike kamwe kwa programu za kawaida."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"Simamia misimbo kuu ya sauti"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Huruhusu mmiliki kusimamia misimbo kuu ya utambuzi wa neno tekelezi la sauti. Haipaswi kuhitajika kwa programu za kawaida kamwe."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"fungisha kwenye mwonekano wa mbali"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Huruhusu mtumiaji kujifungia kiolesura cha kiwango cha juu cha mwonekano wa mbali. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"funga kwenye huduma ya widget"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Huruhusu programu kutumia vyombo vyovyote vya habari vilivyosakinishwa ili kusimbua kwa ajili ya kucheza tena."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"dhibiti vitambulisho vinavyoaminika"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Huruhusu programu kusakinisha na kusanidua vyeti vya CA kama vitambulisho vinavyoaminika."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"endesha programu wakati kifaa hakifanyi kitu"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ruhusa hii huwezesha mfumo wa Android kuendesha programu chini kwa chini wakati kifaa hakitumiki."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"endesha kazi ya chini chini iliyopangwa ya programu"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Idhini hii huruhusu mfumo wa Android kuendesha programu chini chini ikipokea ombi."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"soma/andika kwa vyanzo vinavyomilikiwa na diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Inaruhusu programu kusoma na kuandika kwa chanzo chochote kinachomilikiwa na kikundi cha diag; kwa mfano, faili katika /dev. Hii inaweza kuathiri udhabiti na usalama wa mfumo. Hii inapaswa kutumiwa TU kwa utambuzi mahsusi wa maunzi na mtengenezaji au opareta."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"wezesha au lemeza vijenzi vya programu"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Inaruhusu programu kunasa na kuelekeza sauti kwingine."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Kutambua neno tekelezi"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Inaruhusu programu kunasa sauti kwa ajili ya utambuzi wa Neno Tekelezi. Kunasa kunaweza kukafanyika chinichini lakini hakutazuia unasaji mwingine wa sauti (kwa mfano Kamkoda)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Uelekezaji wa Sauti"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Huruhusu programu kudhibiti uelekezaji wa sauti moja kwa moja na kupuuza maamuzi ya sera ya sauti."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"nasa sauti ya video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Inaruhusu programu kunasa na kuelekeza video kwingine."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"nasa sauti ya video kwa usalama"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Huruhusu programu kudhibiti kilinda-funguo."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Sikiliza mabadiliko ya hali ya kuaminiwa."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Huruhusu programu kusikiliza mabadiliko katika hali ya kuaminiwa."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Toa wakala wa uaminifu."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Huruhusu programu kutoa wakala wa uaminifu."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Funga kwenye huduma ya dalali wa kuaminiwa"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Huruhusu programu kufungamanisha kwenye huduma ya dalali wa kuaminiwa."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Ingiliana na sasisho na mfumo wa kurejesha"</string>
diff --git a/core/res/res/values-television/themes.xml b/core/res/res/values-television/themes.xml
index 6e17cdd3..f92ff40 100644
--- a/core/res/res/values-television/themes.xml
+++ b/core/res/res/values-television/themes.xml
@@ -18,6 +18,6 @@
<style name="Theme.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" />
<style name="Theme.Holo.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
<style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
- <style name="Theme.Quantum.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
- <style name="Theme.Quantum.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
+ <style name="Theme.Material.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
+ <style name="Theme.Material.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index d235eaa..feabf4f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
<string name="android_system_label" msgid="6577375335728551336">"ระบบแอนดรอยด์"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"ส่วนตัว"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"ที่ทำงาน"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"แอปส่วนตัว"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"แอนดรอยด์สำหรับการทำงาน"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"บริการที่ต้องเสียค่าใช้จ่าย"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"ทำสิ่งที่คุณต้องเสียค่าใช้จ่าย"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"ข้อความของคุณ"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของวอลเปเปอร์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"เชื่อมโยงกับโปรแกรมโต้ตอบด้วยเสียง"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"อนุญาตให้ผู้ใช้อุปกรณ์เชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการโต้ตอบด้วยเสียง ไม่จำเป็นสำหรับแอปทั่วไป"</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"จัดการเสียงพูดวลีคำหลัก"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"ให้ผู้ใช้อุปกรณ์สามารถจัดการวลีคำหลักสำหรับการตรวจหาเสียงพูดคำที่นิยม ไม่จำเป็นสำหรับแอปทั่วไป"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ผูกกับจอแสดงผลระยะไกล"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"อนุญาตให้ผู้ใช้ผูกกับอินเทอร์เฟซระดับสูงสุดของจอแสดงผลระยะไกล ซึ่งแอปพลิเคชันทั่วไปไม่จำเป็นต้องใช้"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"เชื่อมโยงกับบริการวิดเจ็ต"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"อนุญาตให้แอปพลิเคชันใช้ตัวถอดรหัสสื่อใดก็ได้ที่ติดตั้งไว้เพื่อถอดรหัสสำหรับการเล่น"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"จัดการข้อมูลรับรองที่เชื่อถือได้"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"อนุญาตให้แอปติดตั้งและถอนการติดตั้งใบรับรอง CA ในฐานะข้อมูลรับรองที่เชื่อถือได้"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"เรียกใช้แอปพลิเคชันในระหว่างที่ไม่ได้ใช้งาน"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"สิทธิ์นี้ช่วยให้ระบบแอนดรอยด์สามารถเรียกใช้แอปพลิเคชันในพื้นหลังขณะไม่ได้ใช้งานอุปกรณ์อยู่"</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"เรียกใช้งานเบื้องหลังที่กำหนดเวลาไว้ของแอปพลิเคชัน"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"การอนุญาตนี้ช่วยให้ระบบแอนดรอยด์สามารถเรียกใช้แอปพลิเคชันในเบื้องหลังเมื่อได้รับคำขอ"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"อ่าน/เขียนไปยังรีซอร์สที่เป็นเจ้าของโดยกลุ่มวินิจฉัย"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"อนุญาตให้แอปพลิเคชันอ่านและเขียนไปยังทรัพยากรที่เป็นของกลุ่มวินิจฉัย เช่น ไฟล์ใน /dev การทำเช่นนี้อาจส่งผลต่อความเสถียรและความปลอดภัยของระบบ และควรใช้สำหรับการวินิจฉัยเกี่ยวกับฮาร์ดแวร์โดยเฉพาะที่ทำโดยผู้ผลิตหรือผู้ให้บริการเท่านั้น"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"เปิดหรือปิดใช้งานคอมโพเนนต์ของแอปพลิเคชัน"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"อนุญาตให้แอปบันทึกและเปลี่ยนเส้นทางเอาต์พุตเสียง"</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"การตรวจหาคำที่นิยม"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"อนุญาตให้แอปเก็บเสียงสำหรับการตรวจหาคำที่นิยม การเก็บเสียงสามารถดำเนินการอยู่ในพื้นหลัง แต่ไม่เป็นการป้องกันการเก็บเสียงอื่นๆ (เช่น กล้องวิดีโอ)"</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"การกำหนดเส้นทางเสียง"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"ช่วยให้แอปสามารถควบคุมการกำหนดเส้นทางเสียงได้โดยตรง และแทนที่การตัดสินใจในนโยบายด้านเสียง"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"บันทึกเอาต์พุตวิดีโอ"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"อนุญาตให้แอปบันทึกและเปลี่ยนเส้นทางเอาต์พุตวิดีโอ"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"บันทึกเอาต์พุตเสียงที่ปลอดภัย"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"อนุญาตให้แอปพลิเคชันควบคุมตัวล็อกปุ่มกด"</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"ฟังการเปลี่ยนแปลงของสถานะความน่าเชื่อถือ"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"อนุญาตให้แอปพลิเคชันฟังการเปลี่ยนแปลงที่มีต่อสถานะความน่าเชื่อถือ"</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"เสนอตัวแทนที่เชื่อถือได้"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"ช่วยให้แอปพลิเคชันสามารถเสนอตัวแทนที่เชื่อถือได้"</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"เปิดเมนูการตั้งค่าตัวแทนที่เชื่อถือได้"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"อนุญาตให้แอปพลิเคชันเปิดกิจกรรมที่เปลี่ยนพฤติกรรมตัวแทนที่เชื่อถือได้"</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"ผูกกับบริการของตัวแทนที่เชื่อถือได้"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"อนุญาตให้แอปพลิเคชันผูกกับบริการของตัวแทนที่เชื่อถือได้"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"โต้ตอบกับการอัปเดตและระบบการกู้คืน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 2b7d961..13b629e 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Trabaho"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Mga personal na app"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Mga serbisyong ginagastusan mo"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Gumawa ng mga bagay na magpapagastos sa iyo."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Iyong mga mensahe"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng isang wallpaper. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"i-bind sa isang voice interactor"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Nagbibigay-daan sa may-hawak na i-bind ang top-level na interface ng isang serbisyo sa pakikipag-ugnayan gamit ang boses. Hindi kailanman dapat kailanganin ng mga normal na app."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"pamahalaan ang mga keyphrase ng boses"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Pinapayagan ang holder na pamahalaan ang mga keyphrase para sa pagtukoy ng hotword ng boses. Hindi dapat kailanman kailanganin para sa mga normal na app."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"magpasaklaw sa isang remote na display"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Binibigyang-daan ang may-hawak na masaklaw ang pinakamataas na antas ng interface ng isang remote na display. Hindi dapat kailanman kailanganin ng normal na apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"itali sa serbisyo ng widget"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Pinapayagan ang app na gumamit ng anumang naka-install na media decoder upang mag-decode para sa pag-playback."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"mga pinamamahalaang pinagkakatiwalaang kredensyal"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Pinapayagan ang app na mag-install at mag-uninstall ng mga CA certificate bilang mga pinagkakatiwalaang kredensyal."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"paganahin ang application habang idle"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Nagbibigay-daan ang pahintulot na ito sa Android system na paganahin ang application sa background habang hindi ginagamit ang device."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"patakbuhin ang nakaiskedyul na paggana sa background ng application"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Nagbibigay-daan ang pahintulot na ito sa Android system na paganahin ang application sa background kapag hiniling."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"magbasa/magsulat sa mga mapagkukunang pag-aari ng diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Pinapayagan ang app na magbasa at magsulat sa anumang mapagkukunang pag-aari ng pangkat ng diag; halimbawa, mga file sa /dev. Maaaring potensyal na maapektuhan nito ang katatagan at seguridad ng system. Dapat LAMANG itong gamitin para sa diagnostics na tukoy sa hardware ng tagagawa o operator."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"paganahin o huwag paganahin ang mga bahagi ng app"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Pinapayagan ang app na kumuha at mag-redirect ng audio output."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Paghahanap ng hotword"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Nagbibigay-daan sa app na kumuha ng audio na paghahanapan ng Hotword. Maaaring maisagawa sa background ang pagkuha, ngunit hindi nito pipigilan ang iba pang pagkuha ng audio (hal. Camcorder)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Pagruruta ng Audio"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Pinapayagan ang app na direktang kontrolin ang pagruruta ng audio at i-override ang mga pasya sa patakaran sa audio."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"kumuha ng video output"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Pinapayagan ang app na kumuha at mag-redirect ng video output."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"kumuha ng secure na video output"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Pinapayagan ang isang application na kontrolin ang keyguard."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Makinig sa mga pagbabago sa estado ng trust."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Pinapayagan ang isang application na makinig para sa mga pagbabago sa estado ng trust."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Magbigay ng trust agent."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Pinapayagan ang isang application na magbigay ng trust agent."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Ilunsad ang menu ng mga setting ng trust agent."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Nagbibigay-daan sa isang application na maglunsad ng aktibidad na nagbabago sa pagkilos ng trust agent."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Sumailalim sa isang serbisyo ng trust agent"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Pinapayagan ang isang application na sumailalim sa isang serbisyo ng trust agent."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Makipag-ugnay sa system ng pag-update at pagbawi"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index d5e227e..0c19b03 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Kişisel"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"İş"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Kişisel uygulamalar"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Size maliyet getiren hizmetler"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Size maliyet getirebilecek işlemler yapma."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Mesajlarınız"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Cihazın sahibine, duvar kağıdının en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"bir ses etkileşimi hizmetine bağlanma"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"İzin sahibinin, bir ses etkileşimi hizmetine ait üst düzey arayüze bağlanmasına izin verir. Normal uygulamalar için hiçbir zaman gerekli değildir."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"sesli anahtar ifadeleri yönet"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"İzin sahibine, söylenen özel kelimeleri algılamak için anahtar ifadeleri yönetme izni verir. Normal uygulamalar için hiçbir zaman gerekli olmamalıdır."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"uzak ekrana bağlan"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"İzin sahibine, bir uzak ekranın en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bir widget hizmetine bağla"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Uygulamaya, oynatma kodunu çözmek için herhangi bir yüklü medya kod çözücüyü kullanma izni verir."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"güvenilen kimlik bilgilerini yönetme"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Uygulamaya, güvenilir kimlik bilgileri olarak CA sertifikaları yükleme veya sertifikaların yüklemelerini kaldırma izni verir."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"boşta kaldığında uygulamayı çalıştır"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Bu izin, cihaz kullanımda değilken Android sistemin uygulamayı arka planda çalıştırmasına olanak sağlar."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"uygulamanın planlanan arka plan işini çalıştır"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Bu izin, istendiğinde Android sistemin uygulamayı arka planda çalıştırmasına olanak sağlar."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"sahibi tanılama olan kaynakları oku/bunlara yaz"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Uygulamaya, tanılama grubunun sahip olduğu tüm kaynaklara (örneğin /dev içindeki dosyalar) okuma ve yazma izni verir. Bu işlevin sistem kararlılığını ve güvenliğini olumsuz etkileme olasılığı vardır. Üretici veya operatör tarafından YALNIZCA donanıma özgü tanılama için kullanılmalıdır."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"uygulama bileşenlerini etkinleştir veya devre dışı bırak"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Uygulamaya, ses çıkışını yakalayıp yönlendirme izni verir."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Özel kelime algılama"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Uygulamaya, Özel Kelime algılamak için ses yakalama izni verir. Ses yakalama işlemi arka planda yapılabilir, ancak diğer ses yakalama işlemlerini (ör. kameranın ses kaydını) engellemez."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Ses Yönlendirme"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Uygulamanın ses yönlendirmeyi doğrudan denetlemesine ve ses politikası kararlarını geçersiz kılmasına izin verir."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"video çıkışını yakala"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Uygulamaya, video çıkışını yakalayıp yönlendirme izni verir."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"güvenli video çıkışını yakala"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Bir uygulamaya tuş koruyucuyu denetleme izni verir."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Güven durumundaki değişiklileri dinle."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Bir uygulamanın, güven durumundaki değişiklikleri dinlemesine izin verir."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Güven aracısı sağlama."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Bir uygulamanın güven aracısı sağlamasına izin verir."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Güven aracı hizmetine bağlan"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Bir uygulamanın, güven aracı hizmetine bağlanmasına izin verir."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Güncelleme ve kurtarma sistemiyle etkileşim kur"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 5088a8a..0d56975b 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Особистий профіль"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Службовий профіль"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Особисті додатки"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android для бізнесу"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Служби, які потребують оплати"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Виконувати дії, які потребують оплати."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Ваші повідомл."</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня фонового малюнка. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"підключитися до служби голосової взаємодії"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Додаток зможе підключатися до інтерфейсу верхнього рівня служби голосової взаємодії. Звичайні додатки ніколи не використовують цей дозвіл."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"керувати голосовими ключовими фразами"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Власник може керувати ключовими фразами, які розпізнаватимуться як голосові команди швидкого запуску. Звичайні додатки ніколи не використовують цей дозвіл."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"прив’язуватися до віддаленого екрана"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня віддаленого екрана. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"прив\'язувати до служби віджетів"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Дозволяє програмі використовувати будь-який установлений медіа-декодер для декодування з метою відтворення."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"керувати захищеними обліковими даними"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Дозволяє програмі встановлювати та видаляти сертифікати центру сертифікації (CA) як захищені облікові дані."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"запускати додаток, коли пристрій неактивний"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Маючи цей дозвіл, система Android може запускати додаток у фоновому режимі, коли пристрій не використовується."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"планово запускати додаток у фоновому режимі"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Маючи цей дозвіл, система Android може запускати додаток у фоновому режимі, коли це потрібно."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"чит./зап. на ресури., якими вол. діаг."</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Дозволяє програмі читати та писати на будь-який ресурс, яким володіє діагностична група; наприклад, у файли в папці /dev. Це потенційно може вплинути на стабільність і безпеку системи. Потрібно використовувати ЛИШЕ для певної діагностики обладнання, яку виконує виробник чи оператор."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"вмикати чи вимикати компоненти програми"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Дозволяє програмі отримувати доступ до аудіовиходу й переспрямовувати його."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"виявляти команди швидкого запуску"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Дозволяє програмі записувати аудіо для виявлення команд швидкого запуску. Запис відбуватиметься у фоновому режимі й не перешкоджатиме запису іншого аудіо (напр., з відеокамери)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Маршрутизація аудіо"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Додаток може безпосередньо керувати маршрутизацією аудіо та змінювати правила керування аудіо."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"отримувати доступ до відеовиходу"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Дозволяє програмі отримувати доступ до відеовиходу й переспрямовувати його."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"отримувати доступ до захищеного відеовиходу"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Дозволяє програмі керувати клавіатурою."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Відстежувати зміни в стані довіри."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Дозволяє додатку відстежувати зміни в стані довіри."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Призначення довірчого агента."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Додаток може призначати довірчого агента."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Запустити меню налаштувань довірчого агента"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Додаток може запускати функцію, яка змінює поведінку довірчого агента."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Прив’язуватися до служби довірчих агентів"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Дозволяє додатку прив’язуватися до служби довірчих агентів."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Взаємодіяти з оновленнями системи та системою відновлення."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 7961f84..dd13b45 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
<string name="android_system_label" msgid="6577375335728551336">"Hệ thống Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Cá nhân"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Cơ quan"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Ứng dụng cá nhân"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Dịch vụ tính tiền của bạn"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Thực hiện những tác vụ mà bạn có thể phải trả tiền."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Tin nhắn của bạn"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của hình nền. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"liên kết với trình tương tác bằng giọng nói"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ tương tác bằng giọng nói. Không cần thiết cho các ứng dụng thông thường."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"quản lý cụm từ khóa bằng giọng nói"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Cho phép chủ sở hữu quản lý các cụm từ khóa để phát hiện từ nóng bằng giọng nói. Không bao giờ cần cho ứng dụng thông thường."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"liên kết với màn hình từ xa"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của màn hình từ xa. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"liên kết với dịch vụ tiện ích con"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Cho phép ứng dụng sử dụng bất kỳ trình giải mã phương tiện nào đã cài đặt nhằm giải mã để phát lại."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"quản lý thông tin xác thực đáng tin cậy"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Cho phép ứng dụng cài đặt và gỡ cài đặt chứng chỉ CA dưới dạng thông tin xác thực đáng tin cậy."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"chạy ứng dụng trong thời gian rảnh"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Quyền này cho phép hệ thống Android chạy ứng dụng trong nền khi thiết bị không được sử dụng."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"chạy công việc trong nền đã lên lịch của ứng dụng"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Quyền này cho phép hệ thống Android chạy ứng dụng trong nền khi được yêu cầu."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"đọc/ghi vào tài nguyên do chẩn đoán sở hữu"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Cho phép ứng dụng đọc và ghi vào bất kỳ tài nguyên nào do nhóm chẩn đoán sở hữu; ví dụ: các tệp trong /dev. Quyền này có thể ảnh hưởng đến sự ổn định và tính bảo mật của hệ thống. CHỈ nên sử dụng quyền này cho các chẩn đoán phần cứng cụ thể của nhà sản xuất hoặc nhà cung cấp."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"bật hoặc tắt cấu phần ứng dụng"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Cho phép ứng dụng thu thập và chuyển hướng dữ liệu đầu ra âm thanh."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Phát hiện từ nóng"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Cho phép ứng dụng thu thập dữ liệu âm thanh để phát hiện từ nóng. Quá trình thu thập này có thể diễn ra trong nền nhưng không ngăn các hoạt động thu thập dữ liệu âm thanh khác (ví dụ: máy quay video)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Định tuyến âm thanh"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Cho phép ứng dụng trực tiếp kiểm soát định tuyến âm thanh và ghi đè các quyết định về chính sách âm thanh."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"thu thập dữ liệu đầu ra video"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Cho phép ứng dụng thu thập và chuyển hướng dữ liệu đầu ra video."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"thu thập dữ liệu đầu ra video an toàn"</string>
@@ -1356,6 +1360,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Cho phép ứng dụng kiểm soát tính năng bảo vệ phím."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Quan sát các thay đổi ở trạng thái đáng tin cậy."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Cho phép ứng dụng quan sát các thay đổi ở trạng thái đáng tin cậy."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Cung cấp tác nhân đáng tin cậy."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Cho phép ứng dụng cung cấp tác nhân đáng tin cậy."</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Liên kết với một dịch vụ của đại lý đáng tin cậy"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Cho phép ứng dụng liên kết với một dịch vụ của đại lý đáng tin cậy."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Tương tác với hệ thống khôi phục và bản cập nhật"</string>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 8d82a17..6052fb0 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -36,4 +36,8 @@
<!-- Maximum velocity to initiate a fling, as measured in dips per second. -->
<dimen name="config_viewMaxFlingVelocity">8000dp</dimen>
+ <!-- Number of notifications to keep in the notification service historical archive.
+ Reduced intentionally for watches to retain minimal memory footprint -->
+ <integer name="config_notificationServiceArchiveSize">1</integer>
+
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 5771bd9..3a07366 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -188,8 +188,9 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"个人"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"企业"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"个人应用"</string>
+ <!-- no translation found for managed_profile_label (4287077106125758391) -->
+ <skip />
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"需要您付费的服务"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"执行可能需要您付费的操作。"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"您的信息"</string>
@@ -400,6 +401,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允许用户绑定到壁纸的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"绑定到语音互动器"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"允许应用绑定到语音互动服务的顶级接口。普通应用绝不需要此权限。"</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"管理语音关键短语"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"允许应用管理用于语音启动指令检测的关键短语。普通应用绝不需要此权限。"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"绑定至远程显示屏"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允许应用绑定至远程显示屏的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"绑定到小部件服务"</string>
@@ -443,10 +446,10 @@
<string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"允许应用从系统的各个日志文件中读取信息。这样,应用就可以发现关于您手机使用情况的一般信息,其中可能包含个人信息或隐私信息。"</string>
<string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"使用任何媒体解码器进行播放"</string>
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允许该应用使用任何已安装的媒体解码器进行解码,以便播放媒体。"</string>
- <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理受信任的凭据"</string>
- <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允许应用安装和卸载 CA 证书(作为受信任的凭据)。"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"在设备处于闲置状态时运行应用"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"当设备处于闲置状态时,此权限允许Android系统在后台运行该应用。"</string>
+ <string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的凭据"</string>
+ <string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允许应用安装和卸载CA证书(作为信任的凭据)。"</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"运行应用的排定后台工作"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Android系统收到请求后会在后台运行具有此权限的应用。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"读取/写入诊断所拥有的资源"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"允许应用读取/写入诊断组拥有的所有资源(例如 /dev 中的文件)。这可能会影响系统的稳定性和安全性。此权限仅供制造商或运营商诊断硬件方面的问题时使用。"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"启用或停用应用组件"</string>
@@ -520,6 +523,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"允许该应用捕获和重定向音频输出。"</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"启动指令检测"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"允许应用捕获音频以便检测语音启动指令。捕获操作会在后台进行,但不会妨碍其他音频捕获工具(例如摄像机)。"</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"音频路由"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"允许应用直接控制音频路由以及覆盖音频规范决策。"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"捕获视频输出"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"允许该应用捕获和重定向视频输出。"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"捕获安全视频输出"</string>
@@ -768,7 +773,7 @@
</string-array>
<string-array name="imAddressTypes">
<item msgid="1738585194601476694">"住宅"</item>
- <item msgid="1359644565647383708">"单位"</item>
+ <item msgid="1359644565647383708">"工作"</item>
<item msgid="7868549401053615677">"其他"</item>
<item msgid="3145118944639869809">"自定义"</item>
</string-array>
@@ -823,7 +828,7 @@
<string name="postalTypeOther" msgid="2726111966623584341">"其他"</string>
<string name="imTypeCustom" msgid="2074028755527826046">"自定义"</string>
<string name="imTypeHome" msgid="6241181032954263892">"住宅"</string>
- <string name="imTypeWork" msgid="1371489290242433090">"单位"</string>
+ <string name="imTypeWork" msgid="1371489290242433090">"工作"</string>
<string name="imTypeOther" msgid="5377007495735915478">"其他"</string>
<string name="imProtocolCustom" msgid="6919453836618749992">"自定义"</string>
<string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
@@ -1356,6 +1361,12 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"允许应用控制锁屏。"</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"检测信任状态的变化。"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"允许应用检测信任状态的变化。"</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"提供信任的代理。"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"允许应用提供信任的代理。"</string>
+ <!-- no translation found for permlab_launch_trust_agent_settings (7494179366945389098) -->
+ <skip />
+ <!-- no translation found for permdesc_launch_trust_agent_settings (985453787420853278) -->
+ <skip />
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"绑定至信任的代理服务"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允许应用绑定至信任的代理服务。"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"与更新和恢复系统互动"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index cd0fe61..8e290b5 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"個人"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"公司"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"個人應用程式"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android 企業版"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"付費服務"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"執行需付費的操作或服務。"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"您的訊息"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (不建議一般應用程式使用)。"</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"繫結至語音互動器"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"允許應用程式繫結至語音互動服務的頂層介面,但一般應用程式並不需要使用。"</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"管理語音關鍵字句"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"允許應用程式管理語音關鍵字句,用於偵測語音啟動字詞 (一般應用程式並不需要)。"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"繫結至遠端螢幕"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端屏螢的頂層介面 (不建議一般應用程式使用)。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允許應用程式使用任何已安裝的媒體解碼器為播放解碼。"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的憑證"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允許應用程式安裝 CA 憑證為信任的憑證及解除安裝 CA 憑證。"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"當裝置閒置時執行應用程式"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"當您不使用裝置時,此權限允許 Android 系統在背景執行應用程式。"</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"執行應用程式的預定背景作業"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"這項權限可讓 Android 系統於收到要求時在背景執行應用程式。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"讀取/寫入由診斷應用程式擁有的資源"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"允許應用程式讀取及寫入診斷群組所擁有的任何資源 (例如:位於 /dev 中的檔案)。這可能會影響系統的穩定性及安全性,只應對製造商或網絡供應商所使用的硬件專用診斷程式開放這項權限。"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"啟用或停用應用程式元件"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"允許應用程式擷取及重新導向音頻輸出。"</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"啟動字詞偵測"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"允許應用程式擷取啟動字詞偵測的音頻。擷取操作可以在背景執行,但並未阻止其他音頻擷取 (例如攝錄機)。"</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"音效檔案路由"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"允許應用程式直接控制音效檔案路由及覆寫音效檔案政策決定。"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"擷取視頻輸出"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"允許應用程式擷取及重新導向視頻輸出。"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"擷取安全視頻輸出"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"允許應用程式控制鍵盤鎖。"</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"聽取信任狀態變更。"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"允許應用程式聽取信任狀態的變更。"</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"提供信任的代理程式。"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"允許應用程式提供信任的代理程式。"</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"啟動信任的代理程式設定選單。"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"允許應用程式啟動可變更信任的代理程式行為的活動。"</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"繫結至信任的代理程式服務"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允許應用程式繫結至信任的代理程式服務。"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"與更新和復原系統互動"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index aac387a..6ab2b48 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"超過 999"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"個人"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"公司"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"個人應用程式"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"Android 企業版"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"需要額外費用的服務。"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"執行需付費的作業或服務。"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"您的簡訊"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (一般應用程式不需使用)。"</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"繫結至語音互動器"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"允許應用程式繫結至語音互動服務的頂層介面 (一般應用程式並不需要)。"</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"管理語音關鍵字句"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"允許應用程式管理語音關鍵字句,用於偵測語音啟動字詞 (一般應用程式並不需要)。"</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"繫結至遠端螢幕"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端螢幕的頂層介面 (一般應用程式不需使用)。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允許應用程式使用任何已安裝的媒體解碼器進行解碼以播放影片。"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的憑證"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允許應用程式安裝 CA 憑證 (做為信任的憑證) 及解除安裝 CA 憑證。"</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"當裝置閒置時執行應用程式"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"當裝置處於未使用狀態時,此權限允許 Android 系統在背景執行應用程式。"</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"執行應用程式的預定背景作業"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"這項權限可讓 Android 系統於收到要求時在背景執行應用程式。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"讀寫 diag 擁有的資源"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"允許應用程式讀取或寫入診斷群組擁有的任何資源,例如 /dev 底下的檔案。這可能會影響系統的穩定性和安全性,因此應由製造商或電信業者操作,且只用在特定硬體診斷。"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"啟用或停用應用程式元件"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"允許應用程式擷取及重新導向音訊輸出。"</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"啟動字詞偵測"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"允許應用程式擷取音訊用於啟動字詞偵測。擷取作業可在背景執行,但並未禁止使用其他音訊擷取工具 (例如攝錄影機)。"</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"音訊路由"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"允許應用程式直接控制音訊路由及覆寫音訊政策決定。"</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"擷取視訊輸出"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"允許應用程式擷取及重新導向視訊輸出。"</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"擷取安全視訊輸出"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"允許應用程式控制鍵盤鎖。"</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"接聽信任狀態變更。"</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"允許應用程式接聽信任狀態變更。"</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"提供信任的代理程式。"</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"允許應用程式提供信任的代理程式。"</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"啟動信任的代理程式設定選單。"</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"允許應用程式啟動可變更信任的代理程式行為的活動。"</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"繫結至信任的代理程式服務"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"允許應用程式繫結至信任的代理程式服務。"</string>
<string name="permlab_recovery" msgid="3157024487744125846">"與更新和還原系統互動"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index ef25010..07238c3 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -188,8 +188,8 @@
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
<string name="android_system_label" msgid="6577375335728551336">"Uhlelo lwe-Android"</string>
- <string name="user_owner_label" msgid="2804351898001038951">"Okomuntu siqu"</string>
- <string name="managed_profile_label" msgid="6260850669674791528">"Umsebenzi"</string>
+ <string name="user_owner_label" msgid="6465364741001216388">"Izinhlelo zokusebenza zomuntu siqu"</string>
+ <string name="managed_profile_label" msgid="4287077106125758391">"I-Android Work"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Amasevisi abiza imali"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Yenza izinto ezingakudla imali."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Imiyalezo yakho"</string>
@@ -400,6 +400,8 @@
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lwephephadonga. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
<string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"hlanganisa kusisebenzisani sezwi"</string>
<string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Ivumela umbambi ukuhlanganisa isixhumi esibonakalayo sesevisi yokusebenzisana yezwi. Akufanele kudingekele izinhlelo zokusebenza ezivamile."</string>
+ <string name="permlab_manageVoiceKeyphrases" msgid="1252285102392793548">"phatha amabinzana angukhiye wezwi"</string>
+ <string name="permdesc_manageVoiceKeyphrases" msgid="8476560722907530008">"Ivumela isibambi ukuthi siphathe amabinzana angukhiye wokutholwa kwe-hotword yezwi. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bophezela kusibonisi sesilawuli kude"</string>
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ivumela umbambi ukuhlanganisa isixhumi esibonakalayo esisezingeni eliphezulu sesibonisi sesilawuli kude. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bophezela kube isevisi yesinqunjana"</string>
@@ -445,8 +447,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ivumela uhlelo lokusebenza ukusebenzisa noma isiphi isiqophi semidiya esifakiwe ukuqopha ukudlala."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"phatha ukuqinisekisa okuthenjiwe"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ivumela uhlelo lokusebenza ukuthi lifake liphinde likhiphe izitifiketi ze-CA njengokuqinisekiswa okuthenjiwe."</string>
- <string name="permlab_bindIdleService" msgid="816311765497613780">"qalisa uhlelo lokusebenza ngesikhathi sokungenzi lutho"</string>
- <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Le mvume ivumela isistimu ye-Android ukuthi iqalise uhlelo lokusebenza ngemuva ngenkathi idivayisi ingasebenzi."</string>
+ <string name="permlab_bindJobService" msgid="3637568367978271086">"qalisa umsebenzi ongemuva oshejuliwe wohlelo lokusebenza"</string>
+ <string name="permdesc_bindJobService" msgid="3473288460524119838">"Le mvume ivumela isistimu ye-Android ukuthi iqalise uhlelo lokusebenza ngemuva uma icelwa."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"funda/bhalela emithombweni ephethwe idayegi"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Ivumela uhlelo lokusebenza ukufunda nokubhala kunoma yimuphi umthombo weqembu ledayegi; ngokwesibonelo, amafayela akwi/dev. Lokhu kungase kuthinte kakhulu ukuba nokuphepha kohlelo. Lokhu kumele kusebenziselwe KUPHELA ukuhlola ihadiwe okucacile ngumkhiqizi noma u-opheretha."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"vumela noma vimbela izingxenye zensiza"</string>
@@ -520,6 +522,8 @@
<string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"Kuvumela uhlelo lokusebenza ukuba lushuthe futhi luqondise kabusha okukhipha umsindo."</string>
<string name="permlab_captureAudioHotword" msgid="1890553935650349808">"Ukutholwa kwe-Hotword"</string>
<string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"Ivumela uhlelo lokusebenza ukuthi lishuthele umsindo ukutholwa kwe-Hotword. Ukushutha kungenzeka ngemuva kodwa akuvimbeli okunye ukushutha komsindo (isb. i-Camcorder)."</string>
+ <string name="permlab_modifyAudioRouting" msgid="7738060354490807723">"Umazila womsindo"</string>
+ <string name="permdesc_modifyAudioRouting" msgid="7205731074267199735">"Ivumela uhlelo lokusebenza ukulawla ngqo umzila womsindo nokubhala ngaphezulu izinqumo zenqubomgomo zomsindo."</string>
<string name="permlab_captureVideoOutput" msgid="2246828773589094023">"shutha okokukhipha ividiyo"</string>
<string name="permdesc_captureVideoOutput" msgid="359481658034149860">"Kuvumela uhlelo lokusebenza ukuba lushuthe futhi luqondise kabusha okukhipha ividiyo."</string>
<string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"shutha okukhipha ividiyo ephephile"</string>
@@ -1356,6 +1360,10 @@
<string name="permdesc_control_keyguard" msgid="3043732290518629061">"Ivumela uhlelo lokusebenza ukuthi lulawule ukhiye wokuqapha."</string>
<string name="permlab_trust_listener" msgid="1765718054003704476">"Lalela izinguquko zesimo sokuthemba."</string>
<string name="permdesc_trust_listener" msgid="8233895334214716864">"Ivumela uhlelo lokusebenza ukuthi lilalelele izinguquko kusimo sethemba."</string>
+ <string name="permlab_provide_trust_agent" msgid="5465587586091358316">"Nikeza umsebenzeli owethembekile."</string>
+ <string name="permdesc_provide_trust_agent" msgid="3865702641053068148">"Ivumela uhlelo lokusebenza ukunikeza umsebenzeli owethembekile."</string>
+ <string name="permlab_launch_trust_agent_settings" msgid="7494179366945389098">"Qalisa imenyu yezilungiselelo zomsebenzeli wethemba."</string>
+ <string name="permdesc_launch_trust_agent_settings" msgid="985453787420853278">"Ivumela uhlelo lokusebenza ukuthi luqalise umsebenzi oguqula ukuziphatha komsebenzeli wethemba."</string>
<string name="permlab_bind_trust_agent_service" msgid="8242093169457695334">"Bophezela kusevisi yomenzeli wethemba"</string>
<string name="permdesc_bind_trust_agent_service" msgid="7041930026024507515">"Ivumela uhlelo lokusebenza ukuthi libophezeleke kusevisi yomenzeli wethemba."</string>
<string name="permlab_recovery" msgid="3157024487744125846">"Ixhumana nesibuyekezo nesistimu yokutakula"</string>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 1de26c7..c3036d5 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -299,188 +299,188 @@
<item>@drawable/quickcontact_badge_overlay_normal_light</item>
<item>@drawable/quickcontact_badge_overlay_pressed_light</item>
- <!-- Quantum assets -->
- <item>@drawable/ab_share_pack_qntm_alpha</item>
- <item>@drawable/ab_solid_shadow_qntm_alpha</item>
- <item>@drawable/btn_cab_done_qntm_alpha</item>
- <item>@drawable/btn_check_to_off_qntm_000</item>
- <item>@drawable/btn_check_to_off_qntm_001</item>
- <item>@drawable/btn_check_to_off_qntm_002</item>
- <item>@drawable/btn_check_to_off_qntm_003</item>
- <item>@drawable/btn_check_to_off_qntm_004</item>
- <item>@drawable/btn_check_to_off_qntm_005</item>
- <item>@drawable/btn_check_to_off_qntm_006</item>
- <item>@drawable/btn_check_to_off_qntm_007</item>
- <item>@drawable/btn_check_to_off_qntm_008</item>
- <item>@drawable/btn_check_to_off_qntm_009</item>
- <item>@drawable/btn_check_to_off_qntm_010</item>
- <item>@drawable/btn_check_to_off_qntm_011</item>
- <item>@drawable/btn_check_to_off_qntm_012</item>
- <item>@drawable/btn_check_to_off_qntm_013</item>
- <item>@drawable/btn_check_to_off_qntm_014</item>
- <item>@drawable/btn_check_to_off_qntm_015</item>
- <item>@drawable/btn_check_to_on_qntm_000</item>
- <item>@drawable/btn_check_to_on_qntm_001</item>
- <item>@drawable/btn_check_to_on_qntm_002</item>
- <item>@drawable/btn_check_to_on_qntm_003</item>
- <item>@drawable/btn_check_to_on_qntm_004</item>
- <item>@drawable/btn_check_to_on_qntm_005</item>
- <item>@drawable/btn_check_to_on_qntm_006</item>
- <item>@drawable/btn_check_to_on_qntm_007</item>
- <item>@drawable/btn_check_to_on_qntm_008</item>
- <item>@drawable/btn_check_to_on_qntm_009</item>
- <item>@drawable/btn_check_to_on_qntm_010</item>
- <item>@drawable/btn_check_to_on_qntm_011</item>
- <item>@drawable/btn_check_to_on_qntm_012</item>
- <item>@drawable/btn_check_to_on_qntm_013</item>
- <item>@drawable/btn_check_to_on_qntm_014</item>
- <item>@drawable/btn_check_to_on_qntm_015</item>
- <item>@drawable/btn_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00000_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00001_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00002_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00003_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00004_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00005_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00006_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00007_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00008_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00009_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00010_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00011_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00012_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00013_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00014_qntm_alpha</item>
- <item>@drawable/btn_radio_anim_00015_qntm_alpha</item>
- <item>@drawable/btn_radio_to_off_qntm_000</item>
- <item>@drawable/btn_radio_to_off_qntm_001</item>
- <item>@drawable/btn_radio_to_off_qntm_002</item>
- <item>@drawable/btn_radio_to_off_qntm_003</item>
- <item>@drawable/btn_radio_to_off_qntm_004</item>
- <item>@drawable/btn_radio_to_off_qntm_005</item>
- <item>@drawable/btn_radio_to_off_qntm_006</item>
- <item>@drawable/btn_radio_to_off_qntm_007</item>
- <item>@drawable/btn_radio_to_off_qntm_008</item>
- <item>@drawable/btn_radio_to_off_qntm_009</item>
- <item>@drawable/btn_radio_to_off_qntm_010</item>
- <item>@drawable/btn_radio_to_off_qntm_011</item>
- <item>@drawable/btn_radio_to_off_qntm_012</item>
- <item>@drawable/btn_radio_to_off_qntm_013</item>
- <item>@drawable/btn_radio_to_off_qntm_014</item>
- <item>@drawable/btn_radio_to_off_qntm_015</item>
- <item>@drawable/btn_radio_to_on_qntm_000</item>
- <item>@drawable/btn_radio_to_on_qntm_001</item>
- <item>@drawable/btn_radio_to_on_qntm_002</item>
- <item>@drawable/btn_radio_to_on_qntm_003</item>
- <item>@drawable/btn_radio_to_on_qntm_004</item>
- <item>@drawable/btn_radio_to_on_qntm_005</item>
- <item>@drawable/btn_radio_to_on_qntm_006</item>
- <item>@drawable/btn_radio_to_on_qntm_007</item>
- <item>@drawable/btn_radio_to_on_qntm_008</item>
- <item>@drawable/btn_radio_to_on_qntm_009</item>
- <item>@drawable/btn_radio_to_on_qntm_010</item>
- <item>@drawable/btn_radio_to_on_qntm_011</item>
- <item>@drawable/btn_radio_to_on_qntm_012</item>
- <item>@drawable/btn_radio_to_on_qntm_013</item>
- <item>@drawable/btn_radio_to_on_qntm_014</item>
- <item>@drawable/btn_radio_to_on_qntm_015</item>
- <item>@drawable/btn_rating_star_off_qntm_alpha</item>
- <item>@drawable/btn_rating_star_on_qntm_alpha</item>
- <item>@drawable/btn_star_qntm_alpha</item>
- <item>@drawable/btn_switch_to_off_qntm_000</item>
- <item>@drawable/btn_switch_to_off_qntm_001</item>
- <item>@drawable/btn_switch_to_off_qntm_002</item>
- <item>@drawable/btn_switch_to_off_qntm_003</item>
- <item>@drawable/btn_switch_to_off_qntm_004</item>
- <item>@drawable/btn_switch_to_off_qntm_005</item>
- <item>@drawable/btn_switch_to_off_qntm_006</item>
- <item>@drawable/btn_switch_to_off_qntm_007</item>
- <item>@drawable/btn_switch_to_off_qntm_008</item>
- <item>@drawable/btn_switch_to_off_qntm_009</item>
- <item>@drawable/btn_switch_to_off_qntm_010</item>
- <item>@drawable/btn_switch_to_off_qntm_011</item>
- <item>@drawable/btn_switch_to_off_qntm_012</item>
- <item>@drawable/btn_switch_to_off_qntm_013</item>
- <item>@drawable/btn_switch_to_off_qntm_014</item>
- <item>@drawable/btn_switch_to_on_qntm_000</item>
- <item>@drawable/btn_switch_to_on_qntm_001</item>
- <item>@drawable/btn_switch_to_on_qntm_002</item>
- <item>@drawable/btn_switch_to_on_qntm_003</item>
- <item>@drawable/btn_switch_to_on_qntm_004</item>
- <item>@drawable/btn_switch_to_on_qntm_005</item>
- <item>@drawable/btn_switch_to_on_qntm_006</item>
- <item>@drawable/btn_switch_to_on_qntm_007</item>
- <item>@drawable/btn_switch_to_on_qntm_008</item>
- <item>@drawable/btn_switch_to_on_qntm_009</item>
- <item>@drawable/btn_switch_to_on_qntm_010</item>
- <item>@drawable/btn_switch_to_on_qntm_011</item>
- <item>@drawable/btn_switch_to_on_qntm_012</item>
- <item>@drawable/btn_switch_to_on_qntm_013</item>
- <item>@drawable/btn_switch_to_on_qntm_014</item>
- <item>@drawable/btn_toggle_indicator_qntm_alpha</item>
- <item>@drawable/btn_toggle_qntm_alpha</item>
- <item>@drawable/expander_close_qntm_alpha</item>
- <item>@drawable/expander_open_qntm_alpha</item>
- <item>@drawable/fastscroll_thumb_qntm_alpha</item>
- <item>@drawable/fastscroll_track_qntm_alpha</item>
- <item>@drawable/ic_ab_back_qntm_am_alpha</item>
- <item>@drawable/ic_cab_done_qntm_alpha</item>
- <item>@drawable/ic_clear_qntm_alpha</item>
- <item>@drawable/ic_commit_search_api_qntm_alpha</item>
- <item>@drawable/ic_dialog_alert_qntm_alpha</item>
- <item>@drawable/ic_find_next_qntm_alpha</item>
- <item>@drawable/ic_find_previous_qntm_alpha</item>
- <item>@drawable/ic_go_search_api_qntm_alpha</item>
- <item>@drawable/ic_media_route_disabled_qntm_alpha</item>
- <item>@drawable/ic_media_route_off_qntm_alpha</item>
- <item>@drawable/ic_media_route_on_0_qntm_alpha</item>
- <item>@drawable/ic_media_route_on_1_qntm_alpha</item>
- <item>@drawable/ic_media_route_on_2_qntm_alpha</item>
- <item>@drawable/ic_media_route_on_qntm_alpha</item>
- <item>@drawable/ic_menu_copy_qntm_am_alpha</item>
- <item>@drawable/ic_menu_cut_qntm_alpha</item>
- <item>@drawable/ic_menu_find_qntm_alpha</item>
- <item>@drawable/ic_menu_moreoverflow_qntm_alpha</item>
- <item>@drawable/ic_menu_paste_qntm_am_alpha</item>
- <item>@drawable/ic_menu_search_qntm_alpha</item>
- <item>@drawable/ic_menu_selectall_qntm_alpha</item>
- <item>@drawable/ic_menu_share_qntm_alpha</item>
- <item>@drawable/ic_search_api_qntm_alpha</item>
- <item>@drawable/ic_voice_search_api_qntm_alpha</item>
- <item>@drawable/list_divider_qntm_alpha</item>
- <item>@drawable/list_section_divider_qntm_alpha</item>
- <item>@drawable/popup_background_qntm_mult</item>
- <item>@drawable/progress_primary_qntm_alpha</item>
- <item>@drawable/progress_qntm_alpha</item>
- <item>@drawable/scrollbar_handle_qntm_alpha</item>
- <item>@drawable/scrubber_control_from_pressed_qntm_000</item>
- <item>@drawable/scrubber_control_from_pressed_qntm_001</item>
- <item>@drawable/scrubber_control_from_pressed_qntm_002</item>
- <item>@drawable/scrubber_control_from_pressed_qntm_003</item>
- <item>@drawable/scrubber_control_from_pressed_qntm_004</item>
- <item>@drawable/scrubber_control_from_pressed_qntm_005</item>
- <item>@drawable/scrubber_control_off_pressed_qntm_alpha</item>
- <item>@drawable/scrubber_control_off_qntm_alpha</item>
- <item>@drawable/scrubber_control_on_pressed_qntm_alpha</item>
- <item>@drawable/scrubber_control_on_qntm_alpha</item>
- <item>@drawable/scrubber_control_to_pressed_qntm_000</item>
- <item>@drawable/scrubber_control_to_pressed_qntm_001</item>
- <item>@drawable/scrubber_control_to_pressed_qntm_002</item>
- <item>@drawable/scrubber_control_to_pressed_qntm_003</item>
- <item>@drawable/scrubber_control_to_pressed_qntm_004</item>
- <item>@drawable/scrubber_control_to_pressed_qntm_005</item>
- <item>@drawable/scrubber_primary_qntm_alpha</item>
- <item>@drawable/scrubber_track_qntm_alpha</item>
- <item>@drawable/spinner_qntm_am_alpha</item>
- <item>@drawable/switch_track_qntm_alpha</item>
- <item>@drawable/text_cursor_qntm_alpha</item>
- <item>@drawable/textfield_activated_qntm_alpha</item>
- <item>@drawable/textfield_default_qntm_alpha</item>
- <item>@drawable/textfield_search_activated_qntm_alpha</item>
- <item>@drawable/textfield_search_default_qntm_alpha</item>
- <item>@drawable/text_select_handle_left_qntm_alpha</item>
- <item>@drawable/text_select_handle_middle_qntm_alpha</item>
- <item>@drawable/text_select_handle_right_qntm_alpha</item>
+ <!-- Material assets -->
+ <item>@drawable/ab_share_pack_mtrl_alpha</item>
+ <item>@drawable/ab_solid_shadow_mtrl_alpha</item>
+ <item>@drawable/btn_cab_done_mtrl_alpha</item>
+ <item>@drawable/btn_check_to_off_mtrl_000</item>
+ <item>@drawable/btn_check_to_off_mtrl_001</item>
+ <item>@drawable/btn_check_to_off_mtrl_002</item>
+ <item>@drawable/btn_check_to_off_mtrl_003</item>
+ <item>@drawable/btn_check_to_off_mtrl_004</item>
+ <item>@drawable/btn_check_to_off_mtrl_005</item>
+ <item>@drawable/btn_check_to_off_mtrl_006</item>
+ <item>@drawable/btn_check_to_off_mtrl_007</item>
+ <item>@drawable/btn_check_to_off_mtrl_008</item>
+ <item>@drawable/btn_check_to_off_mtrl_009</item>
+ <item>@drawable/btn_check_to_off_mtrl_010</item>
+ <item>@drawable/btn_check_to_off_mtrl_011</item>
+ <item>@drawable/btn_check_to_off_mtrl_012</item>
+ <item>@drawable/btn_check_to_off_mtrl_013</item>
+ <item>@drawable/btn_check_to_off_mtrl_014</item>
+ <item>@drawable/btn_check_to_off_mtrl_015</item>
+ <item>@drawable/btn_check_to_on_mtrl_000</item>
+ <item>@drawable/btn_check_to_on_mtrl_001</item>
+ <item>@drawable/btn_check_to_on_mtrl_002</item>
+ <item>@drawable/btn_check_to_on_mtrl_003</item>
+ <item>@drawable/btn_check_to_on_mtrl_004</item>
+ <item>@drawable/btn_check_to_on_mtrl_005</item>
+ <item>@drawable/btn_check_to_on_mtrl_006</item>
+ <item>@drawable/btn_check_to_on_mtrl_007</item>
+ <item>@drawable/btn_check_to_on_mtrl_008</item>
+ <item>@drawable/btn_check_to_on_mtrl_009</item>
+ <item>@drawable/btn_check_to_on_mtrl_010</item>
+ <item>@drawable/btn_check_to_on_mtrl_011</item>
+ <item>@drawable/btn_check_to_on_mtrl_012</item>
+ <item>@drawable/btn_check_to_on_mtrl_013</item>
+ <item>@drawable/btn_check_to_on_mtrl_014</item>
+ <item>@drawable/btn_check_to_on_mtrl_015</item>
+ <item>@drawable/btn_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00000_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00001_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00002_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00003_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00004_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00005_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00006_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00007_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00008_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00009_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00010_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00011_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00012_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00013_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00014_mtrl_alpha</item>
+ <item>@drawable/btn_radio_anim_00015_mtrl_alpha</item>
+ <item>@drawable/btn_radio_to_off_mtrl_000</item>
+ <item>@drawable/btn_radio_to_off_mtrl_001</item>
+ <item>@drawable/btn_radio_to_off_mtrl_002</item>
+ <item>@drawable/btn_radio_to_off_mtrl_003</item>
+ <item>@drawable/btn_radio_to_off_mtrl_004</item>
+ <item>@drawable/btn_radio_to_off_mtrl_005</item>
+ <item>@drawable/btn_radio_to_off_mtrl_006</item>
+ <item>@drawable/btn_radio_to_off_mtrl_007</item>
+ <item>@drawable/btn_radio_to_off_mtrl_008</item>
+ <item>@drawable/btn_radio_to_off_mtrl_009</item>
+ <item>@drawable/btn_radio_to_off_mtrl_010</item>
+ <item>@drawable/btn_radio_to_off_mtrl_011</item>
+ <item>@drawable/btn_radio_to_off_mtrl_012</item>
+ <item>@drawable/btn_radio_to_off_mtrl_013</item>
+ <item>@drawable/btn_radio_to_off_mtrl_014</item>
+ <item>@drawable/btn_radio_to_off_mtrl_015</item>
+ <item>@drawable/btn_radio_to_on_mtrl_000</item>
+ <item>@drawable/btn_radio_to_on_mtrl_001</item>
+ <item>@drawable/btn_radio_to_on_mtrl_002</item>
+ <item>@drawable/btn_radio_to_on_mtrl_003</item>
+ <item>@drawable/btn_radio_to_on_mtrl_004</item>
+ <item>@drawable/btn_radio_to_on_mtrl_005</item>
+ <item>@drawable/btn_radio_to_on_mtrl_006</item>
+ <item>@drawable/btn_radio_to_on_mtrl_007</item>
+ <item>@drawable/btn_radio_to_on_mtrl_008</item>
+ <item>@drawable/btn_radio_to_on_mtrl_009</item>
+ <item>@drawable/btn_radio_to_on_mtrl_010</item>
+ <item>@drawable/btn_radio_to_on_mtrl_011</item>
+ <item>@drawable/btn_radio_to_on_mtrl_012</item>
+ <item>@drawable/btn_radio_to_on_mtrl_013</item>
+ <item>@drawable/btn_radio_to_on_mtrl_014</item>
+ <item>@drawable/btn_radio_to_on_mtrl_015</item>
+ <item>@drawable/btn_rating_star_off_mtrl_alpha</item>
+ <item>@drawable/btn_rating_star_on_mtrl_alpha</item>
+ <item>@drawable/btn_star_mtrl_alpha</item>
+ <item>@drawable/btn_switch_to_off_mtrl_000</item>
+ <item>@drawable/btn_switch_to_off_mtrl_001</item>
+ <item>@drawable/btn_switch_to_off_mtrl_002</item>
+ <item>@drawable/btn_switch_to_off_mtrl_003</item>
+ <item>@drawable/btn_switch_to_off_mtrl_004</item>
+ <item>@drawable/btn_switch_to_off_mtrl_005</item>
+ <item>@drawable/btn_switch_to_off_mtrl_006</item>
+ <item>@drawable/btn_switch_to_off_mtrl_007</item>
+ <item>@drawable/btn_switch_to_off_mtrl_008</item>
+ <item>@drawable/btn_switch_to_off_mtrl_009</item>
+ <item>@drawable/btn_switch_to_off_mtrl_010</item>
+ <item>@drawable/btn_switch_to_off_mtrl_011</item>
+ <item>@drawable/btn_switch_to_off_mtrl_012</item>
+ <item>@drawable/btn_switch_to_off_mtrl_013</item>
+ <item>@drawable/btn_switch_to_off_mtrl_014</item>
+ <item>@drawable/btn_switch_to_on_mtrl_000</item>
+ <item>@drawable/btn_switch_to_on_mtrl_001</item>
+ <item>@drawable/btn_switch_to_on_mtrl_002</item>
+ <item>@drawable/btn_switch_to_on_mtrl_003</item>
+ <item>@drawable/btn_switch_to_on_mtrl_004</item>
+ <item>@drawable/btn_switch_to_on_mtrl_005</item>
+ <item>@drawable/btn_switch_to_on_mtrl_006</item>
+ <item>@drawable/btn_switch_to_on_mtrl_007</item>
+ <item>@drawable/btn_switch_to_on_mtrl_008</item>
+ <item>@drawable/btn_switch_to_on_mtrl_009</item>
+ <item>@drawable/btn_switch_to_on_mtrl_010</item>
+ <item>@drawable/btn_switch_to_on_mtrl_011</item>
+ <item>@drawable/btn_switch_to_on_mtrl_012</item>
+ <item>@drawable/btn_switch_to_on_mtrl_013</item>
+ <item>@drawable/btn_switch_to_on_mtrl_014</item>
+ <item>@drawable/btn_toggle_indicator_mtrl_alpha</item>
+ <item>@drawable/btn_toggle_mtrl_alpha</item>
+ <item>@drawable/expander_close_mtrl_alpha</item>
+ <item>@drawable/expander_open_mtrl_alpha</item>
+ <item>@drawable/fastscroll_thumb_mtrl_alpha</item>
+ <item>@drawable/fastscroll_track_mtrl_alpha</item>
+ <item>@drawable/ic_ab_back_mtrl_am_alpha</item>
+ <item>@drawable/ic_cab_done_mtrl_alpha</item>
+ <item>@drawable/ic_clear_mtrl_alpha</item>
+ <item>@drawable/ic_commit_search_api_mtrl_alpha</item>
+ <item>@drawable/ic_dialog_alert_mtrl_alpha</item>
+ <item>@drawable/ic_find_next_mtrl_alpha</item>
+ <item>@drawable/ic_find_previous_mtrl_alpha</item>
+ <item>@drawable/ic_go_search_api_mtrl_alpha</item>
+ <item>@drawable/ic_media_route_disabled_mtrl_alpha</item>
+ <item>@drawable/ic_media_route_off_mtrl_alpha</item>
+ <item>@drawable/ic_media_route_on_0_mtrl_alpha</item>
+ <item>@drawable/ic_media_route_on_1_mtrl_alpha</item>
+ <item>@drawable/ic_media_route_on_2_mtrl_alpha</item>
+ <item>@drawable/ic_media_route_on_mtrl_alpha</item>
+ <item>@drawable/ic_menu_copy_mtrl_am_alpha</item>
+ <item>@drawable/ic_menu_cut_mtrl_alpha</item>
+ <item>@drawable/ic_menu_find_mtrl_alpha</item>
+ <item>@drawable/ic_menu_moreoverflow_mtrl_alpha</item>
+ <item>@drawable/ic_menu_paste_mtrl_am_alpha</item>
+ <item>@drawable/ic_menu_search_mtrl_alpha</item>
+ <item>@drawable/ic_menu_selectall_mtrl_alpha</item>
+ <item>@drawable/ic_menu_share_mtrl_alpha</item>
+ <item>@drawable/ic_search_api_mtrl_alpha</item>
+ <item>@drawable/ic_voice_search_api_mtrl_alpha</item>
+ <item>@drawable/list_divider_mtrl_alpha</item>
+ <item>@drawable/list_section_divider_mtrl_alpha</item>
+ <item>@drawable/popup_background_mtrl_mult</item>
+ <item>@drawable/progress_primary_mtrl_alpha</item>
+ <item>@drawable/progress_mtrl_alpha</item>
+ <item>@drawable/scrollbar_handle_mtrl_alpha</item>
+ <item>@drawable/scrubber_control_from_pressed_mtrl_000</item>
+ <item>@drawable/scrubber_control_from_pressed_mtrl_001</item>
+ <item>@drawable/scrubber_control_from_pressed_mtrl_002</item>
+ <item>@drawable/scrubber_control_from_pressed_mtrl_003</item>
+ <item>@drawable/scrubber_control_from_pressed_mtrl_004</item>
+ <item>@drawable/scrubber_control_from_pressed_mtrl_005</item>
+ <item>@drawable/scrubber_control_off_pressed_mtrl_alpha</item>
+ <item>@drawable/scrubber_control_off_mtrl_alpha</item>
+ <item>@drawable/scrubber_control_on_pressed_mtrl_alpha</item>
+ <item>@drawable/scrubber_control_on_mtrl_alpha</item>
+ <item>@drawable/scrubber_control_to_pressed_mtrl_000</item>
+ <item>@drawable/scrubber_control_to_pressed_mtrl_001</item>
+ <item>@drawable/scrubber_control_to_pressed_mtrl_002</item>
+ <item>@drawable/scrubber_control_to_pressed_mtrl_003</item>
+ <item>@drawable/scrubber_control_to_pressed_mtrl_004</item>
+ <item>@drawable/scrubber_control_to_pressed_mtrl_005</item>
+ <item>@drawable/scrubber_primary_mtrl_alpha</item>
+ <item>@drawable/scrubber_track_mtrl_alpha</item>
+ <item>@drawable/spinner_mtrl_am_alpha</item>
+ <item>@drawable/switch_track_mtrl_alpha</item>
+ <item>@drawable/text_cursor_mtrl_alpha</item>
+ <item>@drawable/textfield_activated_mtrl_alpha</item>
+ <item>@drawable/textfield_default_mtrl_alpha</item>
+ <item>@drawable/textfield_search_activated_mtrl_alpha</item>
+ <item>@drawable/textfield_search_default_mtrl_alpha</item>
+ <item>@drawable/text_select_handle_left_mtrl_alpha</item>
+ <item>@drawable/text_select_handle_middle_mtrl_alpha</item>
+ <item>@drawable/text_select_handle_right_mtrl_alpha</item>
</array>
<!-- Do not translate. These are all of the color state list resources that should be
@@ -518,17 +518,17 @@
<item>#00000000</item>
<item>#ffffffff</item>
- <!-- Quantum color state lists -->
- <item>@color/background_cache_hint_selector_quantum_dark</item>
- <item>@color/background_cache_hint_selector_quantum_light</item>
- <item>@color/btn_default_quantum_dark</item>
- <item>@color/btn_default_quantum_light</item>
- <item>@color/primary_text_disable_only_quantum_dark</item>
- <item>@color/primary_text_disable_only_quantum_light</item>
- <item>@color/primary_text_quantum_dark</item>
- <item>@color/primary_text_quantum_light</item>
- <item>@color/search_url_text_quantum_dark</item>
- <item>@color/search_url_text_quantum_light</item>
+ <!-- Material color state lists -->
+ <item>@color/background_cache_hint_selector_material_dark</item>
+ <item>@color/background_cache_hint_selector_material_light</item>
+ <item>@color/btn_default_material_dark</item>
+ <item>@color/btn_default_material_light</item>
+ <item>@color/primary_text_disable_only_material_dark</item>
+ <item>@color/primary_text_disable_only_material_light</item>
+ <item>@color/primary_text_material_dark</item>
+ <item>@color/primary_text_material_light</item>
+ <item>@color/search_url_text_material_dark</item>
+ <item>@color/search_url_text_material_light</item>
</array>
<!-- Used in LocalePicker -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b47a890..8d8f69e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -496,6 +496,12 @@
<!-- Internal layout used internally for window decor -->
<attr name="windowActionBarFullscreenDecorLayout" format="reference" />
+ <!-- The duration, in milliseconds, of the window background fade duration
+ when transitioning into or away from an Activity when called with an
+ Activity Transition. Corresponds to
+ {@link android.view.Window#setTransitionBackgroundFadeDuration(long)}. -->
+ <attr name="windowTransitionBackgroundFadeDuration" format="integer"/>
+
<!-- ============ -->
<!-- Alert Dialog styles -->
<!-- ============ -->
@@ -828,6 +834,8 @@
<attr name="preferenceFragmentPaddingSide" format="dimension" />
<!-- Default style for switch preferences. -->
<attr name="switchPreferenceStyle" format="reference" />
+ <!-- Default style for seekbar preferences. -->
+ <attr name="seekBarPreferenceStyle" format="reference" />
<!-- ============================ -->
<!-- Text selection handle styles -->
@@ -1813,6 +1821,11 @@
Corresponds to {@link android.view.Window#setNavigationBarColor(int)}. -->
<attr name="navigationBarColor" format="color" />
+ <!-- The duration, in milliseconds, of the window background fade duration
+ when transitioning into or away from an Activity when called with an
+ Activity Transition. Corresponds to
+ {@link android.view.Window#setTransitionBackgroundFadeDuration(long)}. -->
+ <attr name="windowTransitionBackgroundFadeDuration" />
</declare-styleable>
<!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -2419,6 +2432,30 @@
<!-- Sets the state-based animator for the View. -->
<attr name="stateListAnimator" format="reference"/>
+
+ <!-- Tint to apply to the background. -->
+ <attr name="backgroundTint" format="color" />
+
+ <!-- Blending mode used to apply the background tint. -->
+ <attr name="backgroundTintMode">
+ <!-- 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. -->
@@ -3008,7 +3045,29 @@
<!-- Indicates the initial checked state of this button. -->
<attr name="checked" format="boolean" />
<!-- Drawable used for the button graphic (e.g. checkbox, radio button, etc). -->
- <attr name="button" format="reference"/>
+ <attr name="button" format="reference" />
+ <!-- Tint to apply to the button graphic. -->
+ <attr name="buttonTint" format="color" />
+ <!-- Blending mode used to apply the button graphic tint. -->
+ <attr name="buttonTintMode">
+ <!-- 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="CheckedTextView">
<!-- Indicates the initial checked state of this text. -->
@@ -3093,6 +3152,28 @@
<!-- 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. -->
@@ -3198,6 +3279,10 @@
<!-- @hide The alpha value (0-255) set on the ImageView's drawable. Equivalent
to calling ImageView.setAlpha(int), not the same as View.setAlpha(float). -->
<attr name="drawableAlpha" format="integer" />
+ <!-- Tint to apply to the image. -->
+ <attr name="tint" />
+ <!-- Blending mode used to apply the image tint. -->
+ <attr name="tintMode" />
</declare-styleable>
<declare-styleable name="ToggleButton">
<!-- The text for the button when it is checked. -->
@@ -3388,6 +3473,98 @@
<!-- Defines if the associated drawables need to be mirrored when in RTL mode.
Default is false -->
<attr name="mirrorForRtl" format="boolean" />
+ <!-- Tint to apply to the progress indicator. -->
+ <attr name="progressTint" format="color" />
+ <!-- Blending mode used to apply the progress indicator tint. -->
+ <attr name="progressTintMode">
+ <!-- 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>
+ <!-- Tint to apply to the progress indicator background. -->
+ <attr name="progressBackgroundTint" format="color" />
+ <!-- Blending mode used to apply the progress indicator background tint. -->
+ <attr name="progressBackgroundTintMode">
+ <!-- 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>
+ <!-- Tint to apply to the secondary progress indicator. -->
+ <attr name="secondaryProgressTint" format="color" />
+ <!-- Blending mode used to apply the secondary progress indicator tint. -->
+ <attr name="secondaryProgressTintMode">
+ <!-- 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>
+ <!-- Tint to apply to the indepterminate progress indicator. -->
+ <attr name="indeterminateTint" format="color" />
+ <!-- Blending mode used to apply the indeterminate progress indicator tint. -->
+ <attr name="indeterminateTintMode">
+ <!-- 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>
+ <!-- Tint to apply to the background. -->
+ <attr name="backgroundTint" />
+ <!-- Blending mode used to apply the background tint. -->
+ <attr name="backgroundTintMode" />
</declare-styleable>
<declare-styleable name="SeekBar">
@@ -3397,6 +3574,28 @@
<attr name="thumbOffset" format="dimension" />
<!-- Whether to split the track and leave a gap for the thumb drawable. -->
<attr name="splitTrack" format="boolean" />
+ <!-- Tint to apply to the button graphic. -->
+ <attr name="thumbTint" format="color" />
+ <!-- Blending mode used to apply the button graphic tint. -->
+ <attr name="thumbTintMode">
+ <!-- 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="StackView">
@@ -3859,8 +4058,11 @@
<attr name="inputType" />
</declare-styleable>
<declare-styleable name="PopupWindow">
+ <!-- The background to use for the popup window. -->
<attr name="popupBackground" format="reference|color" />
+ <!-- The animation style to use for the popup window. -->
<attr name="popupAnimationStyle" format="reference" />
+ <!-- Whether the popup window should overlap its anchor view. -->
<attr name="overlapAnchor" format="boolean" />
</declare-styleable>
<declare-styleable name="ViewAnimator">
@@ -4562,8 +4764,8 @@
<attr name="drawable" />
</declare-styleable>
- <!-- Drawable used to render the Quantum progress indicator. -->
- <declare-styleable name="QuantumProgressDrawable">
+ <!-- Drawable used to render the Material progress indicator. -->
+ <declare-styleable name="MaterialProgressDrawable">
<attr name="visible" />
<attr name="thickness" />
<attr name="innerRadius" />
@@ -4675,12 +4877,8 @@
<!-- Drawable used to show animated touch feedback. -->
<declare-styleable name="RippleDrawable">
- <!-- The tint to use for ripple effects. This attribute is required. -->
- <attr name="tint" />
- <!-- Specifies the Porter-Duff blending mode used to apply the tint. The default value is src_atop, which draws over the opaque parts of the drawable. -->
- <attr name="tintMode" />
- <!-- Whether to pin ripple effects to the center of the drawable. Default value is false. -->
- <attr name="pinned" format="boolean" />
+ <!-- The color to use for ripple effects. This attribute is required. -->
+ <attr name="color" />
</declare-styleable>
<declare-styleable name="ScaleDrawable">
@@ -4776,7 +4974,7 @@
</declare-styleable>
<!-- ========================== -->
- <!-- Vector drawable class -->
+ <!-- VectorDrawable class -->
<!-- ========================== -->
<eat-comment />
@@ -4796,7 +4994,7 @@
<attr name="height" />
</declare-styleable>
- <!-- Defines the group used in Vector Drawables. -->
+ <!-- Defines the group used in VectorDrawables. -->
<declare-styleable name="VectorDrawableGroup">
<!-- The Name of this group -->
<attr name="name" />
@@ -4818,7 +5016,7 @@
<attr name="alpha" />
</declare-styleable>
- <!-- Defines the path used in Vector Drawables. -->
+ <!-- Defines the path used in VectorDrawables. -->
<declare-styleable name="VectorDrawablePath">
<!-- The Name of this path -->
<attr name="name" />
@@ -4859,6 +5057,25 @@
</declare-styleable>
<!-- ========================== -->
+ <!-- AnimatedVectorDrawable class -->
+ <!-- ========================== -->
+ <eat-comment />
+
+ <!-- Define the AnimatedVectorDrawable. -->
+ <declare-styleable name="AnimatedVectorDrawable">
+ <!-- The static vector drawable. -->
+ <attr name="drawable" />
+ </declare-styleable>
+
+ <!-- Defines the target path or group used in the AnimatedVectorDrawable. -->
+ <declare-styleable name="AnimatedVectorDrawableTarget">
+ <!-- The name of this target path or group -->
+ <attr name="name" />
+ <!-- The animation for this target path or group -->
+ <attr name="animation" />
+ </declare-styleable>
+
+ <!-- ========================== -->
<!-- Animation class attributes -->
<!-- ========================== -->
<eat-comment />
@@ -6394,6 +6611,16 @@
<attr name="settingsActivity" />
</declare-styleable>
+ <!-- Use <code>voice-enrollment-application</code>
+ as the root tag of the XML resource that escribes the supported keyphrases (hotwords)
+ by the enrollment application.
+ Described here are the attributes that can be included in that tag. -->
+ <declare-styleable name="VoiceEnrollmentApplication">
+ <attr name="searchKeyphraseId" format="integer" />
+ <attr name="searchKeyphrase" format="string" />
+ <attr name="searchKeyphraseSupportedLocales" format="string" />
+ </declare-styleable>
+
<!-- Attributes used to style the Action Bar. -->
<declare-styleable name="ActionBar">
<!-- The type of navigation to use. -->
@@ -6568,6 +6795,10 @@
<attr name="disableDependentsState" />
</declare-styleable>
+ <declare-styleable name="SeekBarPreference">
+ <attr name="layout" />
+ </declare-styleable>
+
<!-- Use <code>tts-engine</code> as the root tag of the XML resource that
describes a text to speech engine implemented as a subclass of
{@link android.speech.tts.TextToSpeechService}.
@@ -6747,5 +6978,19 @@
<!-- Component name of an activity that allows the user to modify
the settings for this service. -->
<attr name="settingsActivity" />
+ <!-- Type of this service. -->
+ <attr name="tvInputType">
+ <!-- Should be in sync with constant values defined in
+ {@link android.media.tv.TvInputInfo}. -->
+
+ <!-- Virtual input (default) -->
+ <enum name="virtual" value="0" />
+ <!-- HDMI -->
+ <enum name="hdmi" value="1" />
+ <!-- Built-in tuner -->
+ <enum name="tuner" value="2" />
+ <!-- Pass-through -->
+ <enum name="passthrough" value="3" />
+ </attr>
</declare-styleable>
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index acfbe2d..814d8fc 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -898,16 +898,22 @@
android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} to every Intent used to launch
the activity.
- <p>The documentLaunchMode attribute may be assigned one of three values, "none",
- "intoExisting" and "always", described in detail below. For values other than
- <code>none</code> the activity must be defined with
- {@link android.R.attr#launchMode} <code>standard</code> or <code>singleTop</code>.
+ <p>The documentLaunchMode attribute may be assigned one of four values, "none",
+ "intoExisting", "always" and "never", described in detail below. For values other than
+ <code>none</code> and <code>never</code> the activity must be defined with
+ {@link android.R.attr#launchMode} <code>standard</code>.
If this attribute is not specified, <code>none</code> will be used.
Note that <code>none</code> can be overridden at run time if the Intent used
- to launch it contains the flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT}.
+ to launch it contains the flag {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT
+ Intent.FLAG_ACTIVITY_NEW_DOCUMENT}.
Similarly <code>intoExisting</code> will be overridden by the flag
- {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT} combined with
- {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK}. -->
+ {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT
+ Intent.FLAG_ACTIVITY_NEW_DOCUMENT} combined with
+ {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK}. If the value of
+ documentLaunchModes is <code>never</code> then any use of
+.........{@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT
+ Intent.FLAG_ACTIVITY_NEW_DOCUMENT} to launch this activity will be ignored. -->
<attr name="documentLaunchMode">
<!-- The default mode, which will create a new task only when
{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK
@@ -931,8 +937,21 @@
and {@link android.content.Intent#FLAG_ACTIVITY_MULTIPLE_TASK
Intent.FLAG_ACTIVITY_MULTIPLE_TASK} both set. -->
<enum name="always" value="2" />
+ <!-- This activity will not be launched into a new document even if the Intent contains
+ {@link android.content.Intent#FLAG_ACTIVITY_NEW_DOCUMENT
+ Intent.FLAG_ACTIVITY_NEW_DOCUMENT}. This gives the activity writer ultimate
+ control over how their activity is used. Note that applications prior to api
+ 21 will default to documentLaunchMode="none" so only activities that explicitly
+ opt out with <code>"never"</code> may do so. -->
+ <enum name="never" value="3" />
</attr>
+ <!-- The maximum number of entries of tasks rooted at this activity in the recent task list.
+ When this number of entries is reached the least recently used instance of this activity
+ will be removed from recents. The value will be clamped between 1 and 100 inclusive.
+ The default value for this if it is not specified is 15. -->
+ <attr name="maxRecents" format="integer" />
+
<!-- Tasks launched by activities with this attribute will remain in the recent tasks
list until the last activity in the task is completed. When that happens the task
will be automatically removed from the recent tasks list.
@@ -1607,6 +1626,7 @@
<attr name="persistable" />
<attr name="allowEmbedded" />
<attr name="documentLaunchMode" />
+ <attr name="maxRecents" />
<attr name="autoRemoveFromRecents" />
</declare-styleable>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 9bf2ce8..9f6c7ad 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -135,7 +135,6 @@
<color name="notification_action_legacy_color_filter">#ff555555</color>
<color name="notification_media_action_bg">#00000000</color>
- <color name="notification_media_info_bg">#40FFFFFF</color>
<color name="notification_media_progress">#FFFFFFFF</color>
<!-- Keyguard colors -->
diff --git a/core/res/res/values/colors_holo.xml b/core/res/res/values/colors_holo.xml
index d1f4e38..97b4803 100644
--- a/core/res/res/values/colors_holo.xml
+++ b/core/res/res/values/colors_holo.xml
@@ -75,7 +75,7 @@
<!-- A really bright Holo shade of gray -->
<color name="holo_gray_bright">#33CCCCCC</color>
- <!-- Forward compatibility for Quantum-style theme colors -->
+ <!-- Forward compatibility for Material-style theme colors -->
<eat-comment />
<color name="holo_primary_dark">#ff000000</color>
diff --git a/core/res/res/values/colors_legacy.xml b/core/res/res/values/colors_legacy.xml
index 48d4b42..ad22845 100644
--- a/core/res/res/values/colors_legacy.xml
+++ b/core/res/res/values/colors_legacy.xml
@@ -24,7 +24,7 @@
<color name="legacy_selected_highlight">#fff17a0a</color>
<color name="legacy_long_pressed_highlight">#ffffffff</color>
- <!-- Forward compatibility for Quantum-style theme colors -->
+ <!-- Forward compatibility for Material-style theme colors -->
<eat-comment />
<color name="legacy_primary_dark">#ff000000</color>
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
new file mode 100644
index 0000000..7371d4e
--- /dev/null
+++ b/core/res/res/values/colors_material.xml
@@ -0,0 +1,169 @@
+<?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.
+-->
+
+<!-- Colors specific to Material themes. -->
+<resources>
+ <color name="background_material_dark">#ff212121</color>
+ <color name="background_material_light">#fffafafa</color>
+
+ <color name="ripple_material_light">#20444444</color>
+ <color name="ripple_material_dark">#20ffffff</color>
+
+ <color name="button_material_dark">#ff5a595b</color>
+ <color name="button_material_light">#ffd6d7d7</color>
+
+ <color name="bright_foreground_material_dark">@color/white</color>
+ <color name="bright_foreground_material_light">@color/black</color>
+ <!-- White 50% -->
+ <color name="bright_foreground_disabled_material_dark">#80ffffff</color>
+ <!-- Black 50% -->
+ <color name="bright_foreground_disabled_material_light">#80000000</color>
+ <color name="bright_foreground_inverse_material_dark">@color/bright_foreground_material_light</color>
+ <color name="bright_foreground_inverse_material_light">@color/bright_foreground_material_dark</color>
+
+ <color name="dim_foreground_material_dark">#ffbebebe</color>
+ <color name="dim_foreground_material_light">#ff323232</color>
+ <color name="dim_foreground_disabled_material_dark">#80bebebe</color>
+ <color name="dim_foreground_disabled_material_light">#80323232</color>
+
+ <color name="hint_foreground_material_dark">@color/bright_foreground_disabled_material_dark</color>
+ <color name="hint_foreground_material_light">@color/bright_foreground_disabled_material_light</color>
+ <!-- TODO: This is 40% alpha on the default accent color. -->
+ <color name="highlighted_text_material_dark">#6640c4ff</color>
+ <!-- TODO: This is 40% alpha on the default accent color. -->
+ <color name="highlighted_text_material_light">#6640c4ff</color>
+
+ <!-- Text & foreground colors -->
+ <eat-comment />
+
+ <!-- Black 87% -->
+ <color name="primary_text_default_material_light">#de000000</color>
+ <!-- Black 54% -->
+ <color name="secondary_text_material_light">#8a000000</color>
+ <!-- Black 54% (TODO: same as secondary?) -->
+ <color name="tertiary_text_material_light">#8a000000</color>
+
+ <!-- White 87% -->
+ <color name="primary_text_default_material_dark">#deffffff</color>
+ <!-- White 38% -->
+ <color name="secondary_text_material_dark">#61ffffff</color>
+ <!-- White 38% (TODO: same as secondary?) -->
+ <color name="tertiary_text_material_dark">#61ffffff</color>
+
+ <!-- Primary & accent colors -->
+ <eat-comment />
+
+ <color name="material_red_100">#fff4c7c3</color>
+ <color name="material_red_300">#ffe67c73</color>
+ <color name="material_red_500">#ffdb4437</color>
+ <color name="material_red_700">#ffc53929</color>
+ <color name="material_red_A200">#ffff5252</color>
+ <color name="material_red_A400">#ffff1744</color>
+
+ <color name="material_blue_100">#ffc6dafc</color>
+ <color name="material_blue_300">#ff7baaf7</color>
+ <color name="material_blue_500">#ff4285f4</color>
+ <color name="material_blue_700">#ff3367d6</color>
+ <color name="material_blue_A200">#ff448aff</color>
+ <color name="material_blue_A400">#ff2979ff</color>
+
+ <color name="material_light_blue_A200">#ff40c4ff</color>
+
+ <color name="material_teal_100">#ffb2ebf2</color>
+ <color name="material_teal_300">#ff4dd0e1</color>
+ <color name="material_teal_500">#ff00bcd4</color>
+ <color name="material_teal_700">#ff0097a7</color>
+ <color name="material_teal_A200">#ff18ffff</color>
+ <color name="material_teal_A400">#ff00e5ff</color>
+
+ <!-- Accent color used by Settings -->
+ <color name="material_dark_teal_A400">#ff009688</color>
+
+ <color name="material_green_100">#ffb7e1cd</color>
+ <color name="material_green_300">#ff57bb8a</color>
+ <color name="material_green_500">#ff0f9d58</color>
+ <color name="material_green_700">#ff0b8043</color>
+ <color name="material_green_A200">#ff69f0ae</color>
+ <color name="material_green_A400">#ff00e676</color>
+
+ <color name="material_lime_100">#fff0f4c3</color>
+ <color name="material_lime_300">#ffdce775</color>
+ <color name="material_lime_500">#ffcddc39</color>
+ <color name="material_lime_700">#ffafb42b</color>
+ <color name="material_lime_A200">#ffeeff41</color>
+ <color name="material_lime_A400">#ffc6ff00</color>
+
+ <color name="material_yellow_100">#fffce8b2</color>
+ <color name="material_yellow_300">#fff7cb4d</color>
+ <color name="material_yellow_500">#fff4b400</color>
+ <color name="material_yellow_700">#fff09300</color>
+ <color name="material_yellow_A200">#ffffcd40</color>
+ <color name="material_yellow_A400">#ffffbc00</color>
+
+ <color name="material_orange_100">#ffffe0b2</color>
+ <color name="material_orange_300">#ffffb74d</color>
+ <color name="material_orange_500">#ffff9800</color>
+ <color name="material_orange_700">#fff57c00</color>
+ <color name="material_orange_A200">#ffffab40</color>
+ <color name="material_orange_A400">#ffff9100</color>
+
+ <color name="material_deep_orange_100">#fff4c7c3</color>
+ <color name="material_deep_orange_300">#ffe67c73</color>
+ <color name="material_deep_orange_500">#ffff5722</color>
+ <color name="material_deep_orange_700">#ffc53929</color>
+ <color name="material_deep_orange_A200">#ffff5252</color>
+ <color name="material_deep_orange_A400">#ffff1744</color>
+
+ <!-- Neutral colors -->
+ <eat-comment />
+
+ <color name="material_grey_50">#fffafafa</color>
+ <color name="material_grey_100">#fff5f5f5</color>
+ <color name="material_grey_300">#ffeeeeee</color>
+ <color name="material_grey_500">#ffa3a3a3</color>
+ <color name="material_grey_600">#ff757575</color>
+ <color name="material_grey_700">#ff717171</color>
+ <color name="material_grey_900">#ff212121</color>
+
+ <color name="material_blue_grey_50">#ffeceff1</color>
+ <color name="material_blue_grey_100">#ffcfd8dc</color>
+ <color name="material_blue_grey_300">#ff90a4ae</color>
+ <color name="material_blue_grey_400">#ff78909c</color>
+ <color name="material_blue_grey_500">#ff607d8b</color>
+ <color name="material_blue_grey_600">#ff546e7a</color>
+ <color name="material_blue_grey_700">#ff455a64</color>
+ <color name="material_blue_grey_800">#ff37474f</color>
+ <!-- Primary color used by Settings -->
+ <color name="material_blue_grey_900">#ff263238</color>
+ <!-- Primary dark color used by Settings -->
+ <color name="material_blue_grey_950">#ff21272b</color>
+
+ <color name="material_brown_100">#ffd7ccc8</color>
+ <color name="material_brown_300">#ffa1887f</color>
+ <color name="material_brown_500">#ff795548</color>
+ <color name="material_brown_700">#ff5d4037</color>
+
+ <!-- Time picker defaults when no theme is set -->
+ <eat-comment />
+
+ <color name="timepicker_default_background_material">@color/primary_text_default_material_light</color>
+ <color name="timepicker_default_text_color_material">@color/black</color>
+ <color name="timepicker_default_disabled_color_material">@color/bright_foreground_disabled_material_dark</color>
+ <color name="timepicker_default_ampm_selected_background_color_material">@color/material_light_blue_A200</color>
+ <color name="timepicker_default_ampm_unselected_background_color_material">@color/transparent</color>
+ <color name="timepicker_default_selector_color_material">@color/material_light_blue_A200</color>
+ <color name="timepicker_default_numbers_background_color_material">@color/transparent</color>
+</resources>
diff --git a/core/res/res/values/colors_quantum.xml b/core/res/res/values/colors_quantum.xml
deleted file mode 100644
index f49861a..0000000
--- a/core/res/res/values/colors_quantum.xml
+++ /dev/null
@@ -1,163 +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.
--->
-
-<!-- Colors specific to Quantum themes. -->
-<resources>
- <color name="background_quantum_dark">#ff212121</color>
- <color name="background_quantum_light">#fffafafa</color>
-
- <color name="ripple_quantum_light">#20444444</color>
- <color name="ripple_quantum_dark">#20ffffff</color>
-
- <color name="button_quantum_dark">#ff5a595b</color>
- <color name="button_quantum_light">#ffd6d7d7</color>
-
- <color name="bright_foreground_quantum_dark">@color/white</color>
- <color name="bright_foreground_quantum_light">@color/black</color>
- <!-- Black 50% -->
- <color name="bright_foreground_disabled_quantum_dark">#80000000</color>
- <!-- White 50% -->
- <color name="bright_foreground_disabled_quantum_light">#80ffffff</color>
- <color name="bright_foreground_inverse_quantum_dark">@color/bright_foreground_quantum_light</color>
- <color name="bright_foreground_inverse_quantum_light">@color/bright_foreground_quantum_dark</color>
-
- <color name="dim_foreground_quantum_dark">#ffbebebe</color>
- <color name="dim_foreground_quantum_light">#ff323232</color>
- <color name="dim_foreground_disabled_quantum_dark">#80bebebe</color>
- <color name="dim_foreground_disabled_quantum_light">#80323232</color>
-
- <color name="hint_foreground_quantum_dark">@color/bright_foreground_disabled_quantum_dark</color>
- <color name="hint_foreground_quantum_light">@color/bright_foreground_disabled_quantum_light</color>
- <!-- TODO: This is 40% alpha on the default accent color. -->
- <color name="highlighted_text_quantum_dark">#6640c4ff</color>
- <!-- TODO: This is 40% alpha on the default accent color. -->
- <color name="highlighted_text_quantum_light">#6640c4ff</color>
-
- <!-- Text & foreground colors -->
- <eat-comment />
-
- <!-- Black 87% -->
- <color name="primary_text_default_quantum_light">#de000000</color>
- <!-- Black 54% -->
- <color name="secondary_text_quantum_light">#8a000000</color>
- <!-- Black 54% (TODO: same as secondary?) -->
- <color name="tertiary_text_quantum_light">#8a000000</color>
-
- <!-- White 87% -->
- <color name="primary_text_default_quantum_dark">#deffffff</color>
- <!-- White 38% -->
- <color name="secondary_text_quantum_dark">#61ffffff</color>
- <!-- White 38% (TODO: same as secondary?) -->
- <color name="tertiary_text_quantum_dark">#61ffffff</color>
-
- <!-- Primary & accent colors -->
- <eat-comment />
-
- <color name="quantum_red_100">#fff4c7c3</color>
- <color name="quantum_red_300">#ffe67c73</color>
- <color name="quantum_red_500">#ffdb4437</color>
- <color name="quantum_red_700">#ffc53929</color>
- <color name="quantum_red_A200">#ffff5252</color>
- <color name="quantum_red_A400">#ffff1744</color>
-
- <color name="quantum_blue_100">#ffc6dafc</color>
- <color name="quantum_blue_300">#ff7baaf7</color>
- <color name="quantum_blue_500">#ff4285f4</color>
- <color name="quantum_blue_700">#ff3367d6</color>
- <color name="quantum_blue_A200">#ff448aff</color>
- <color name="quantum_blue_A400">#ff2979ff</color>
-
- <color name="quantum_light_blue_A200">#ff40c4ff</color>
-
- <color name="quantum_teal_100">#ffb2ebf2</color>
- <color name="quantum_teal_300">#ff4dd0e1</color>
- <color name="quantum_teal_500">#ff00bcd4</color>
- <color name="quantum_teal_700">#ff0097a7</color>
- <color name="quantum_teal_A200">#ff18ffff</color>
- <color name="quantum_teal_A400">#ff00e5ff</color>
-
- <color name="quantum_green_100">#ffb7e1cd</color>
- <color name="quantum_green_300">#ff57bb8a</color>
- <color name="quantum_green_500">#ff0f9d58</color>
- <color name="quantum_green_700">#ff0b8043</color>
- <color name="quantum_green_A200">#ff69f0ae</color>
- <color name="quantum_green_A400">#ff00e676</color>
-
- <color name="quantum_lime_100">#fff0f4c3</color>
- <color name="quantum_lime_300">#ffdce775</color>
- <color name="quantum_lime_500">#ffcddc39</color>
- <color name="quantum_lime_700">#ffafb42b</color>
- <color name="quantum_lime_A200">#ffeeff41</color>
- <color name="quantum_lime_A400">#ffc6ff00</color>
-
- <color name="quantum_yellow_100">#fffce8b2</color>
- <color name="quantum_yellow_300">#fff7cb4d</color>
- <color name="quantum_yellow_500">#fff4b400</color>
- <color name="quantum_yellow_700">#fff09300</color>
- <color name="quantum_yellow_A200">#ffffcd40</color>
- <color name="quantum_yellow_A400">#ffffbc00</color>
-
- <color name="quantum_orange_100">#ffffe0b2</color>
- <color name="quantum_orange_300">#ffffb74d</color>
- <color name="quantum_orange_500">#ffff9800</color>
- <color name="quantum_orange_700">#fff57c00</color>
- <color name="quantum_orange_A200">#ffffab40</color>
- <color name="quantum_orange_A400">#ffff9100</color>
-
- <color name="quantum_deep_orange_100">#fff4c7c3</color>
- <color name="quantum_deep_orange_300">#ffe67c73</color>
- <color name="quantum_deep_orange_500">#ffff5722</color>
- <color name="quantum_deep_orange_700">#ffc53929</color>
- <color name="quantum_deep_orange_A200">#ffff5252</color>
- <color name="quantum_deep_orange_A400">#ffff1744</color>
-
- <!-- Neutral colors -->
- <eat-comment />
-
- <color name="quantum_grey_50">#fffafafa</color>
- <color name="quantum_grey_100">#fff5f5f5</color>
- <color name="quantum_grey_300">#ffeeeeee</color>
- <color name="quantum_grey_500">#ffa3a3a3</color>
- <color name="quantum_grey_600">#ff757575</color>
- <color name="quantum_grey_700">#ff717171</color>
- <color name="quantum_grey_900">#ff212121</color>
-
- <color name="quantum_blue_grey_50">#ffeceff1</color>
- <color name="quantum_blue_grey_100">#ffcfd8dc</color>
- <color name="quantum_blue_grey_300">#ff90a4ae</color>
- <color name="quantum_blue_grey_400">#ff78909c</color>
- <color name="quantum_blue_grey_500">#ff607d8b</color>
- <color name="quantum_blue_grey_600">#ff546e7a</color>
- <color name="quantum_blue_grey_700">#ff455a64</color>
- <color name="quantum_blue_grey_800">#ff37474f</color>
- <color name="quantum_blue_grey_900">#ff263238</color>
-
- <color name="quantum_brown_100">#ffd7ccc8</color>
- <color name="quantum_brown_300">#ffa1887f</color>
- <color name="quantum_brown_500">#ff795548</color>
- <color name="quantum_brown_700">#ff5d4037</color>
-
- <!-- Time picker defaults when no theme is set -->
- <eat-comment />
-
- <color name="timepicker_default_background_quantum">@color/primary_text_default_quantum_light</color>
- <color name="timepicker_default_text_color_quantum">@color/black</color>
- <color name="timepicker_default_disabled_color_quantum">@color/bright_foreground_disabled_quantum_dark</color>
- <color name="timepicker_default_ampm_selected_background_color_quantum">@color/quantum_light_blue_A200</color>
- <color name="timepicker_default_ampm_unselected_background_color_quantum">@color/transparent</color>
- <color name="timepicker_default_selector_color_quantum">@color/quantum_light_blue_A200</color>
- <color name="timepicker_default_numbers_background_color_quantum">@color/transparent</color>
-</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5555cf6..a4f78bd 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -589,7 +589,7 @@
<!-- Display low battery warning when battery level dips to this value.
Also, the battery stats are flushed to disk when we hit this level. -->
- <integer name="config_criticalBatteryWarningLevel">4</integer>
+ <integer name="config_criticalBatteryWarningLevel">5</integer>
<!-- Shutdown if the battery temperature exceeds (this value * 0.1) Celsius. -->
<integer name="config_shutdownBatteryTemperature">680</integer>
@@ -597,8 +597,9 @@
<!-- Display low battery warning when battery level dips to this value -->
<integer name="config_lowBatteryWarningLevel">15</integer>
- <!-- Close low battery warning when battery level reaches this value -->
- <integer name="config_lowBatteryCloseWarningLevel">20</integer>
+ <!-- Close low battery warning when battery level reaches the lowBatteryWarningLevel
+ plus this -->
+ <integer name="config_lowBatteryCloseWarningBump">5</integer>
<!-- Default color for notification LED. -->
<color name="config_defaultNotificationColor">#ffffffff</color>
@@ -627,6 +628,9 @@
<!-- Default value for LED off time when the battery is low on charge in miliseconds -->
<integer name="config_notificationsBatteryLedOff">2875</integer>
+ <!-- Number of notifications to keep in the notification service historical archive -->
+ <integer name="config_notificationServiceArchiveSize">250</integer>
+
<!-- Allow the menu hard key to be disabled in LockScreen on some devices -->
<bool name="config_disableMenuKeyInLockScreen">false</bool>
@@ -787,6 +791,19 @@
config_enableFusedLocationOverlay is false. -->
<string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string>
+ <!-- Whether to enable Hardware FLP overlay which allows Hardware FLP to be
+ replaced by an app at run-time. When disabled, only the
+ config_hardwareFlpPackageName package will be searched for Hardware Flp,
+ otherwise packages whose signature matches the signatures of
+ config_locationProviderPackageNames will be searched, and the service
+ with the highest version number will be picked. Anyone who wants to
+ disable the overlay mechanism can set it to false.
+ -->
+ <bool name="config_enableHardwareFlpOverlay" translatable="false">true</bool>
+ <!-- Package name providing Hardware Flp. Used only when
+ config_enableHardwareFlpOverlay is false. -->
+ <string name="config_hardwareFlpPackageName" translatable="false">com.android.location.fused</string>
+
<!-- Whether to enable geocoder overlay which allows geocoder to be replaced
by an app at run-time. When disabled, only the
config_geocoderProviderPackageName package will be searched for
@@ -1557,4 +1574,28 @@
<item>users</item>
</string-array>
+ <!-- default telephony hardware configuration for this platform.
+ -->
+ <!-- this string array should be overridden by the device to present a list
+ telephony hardware resource. this is used by the telephony device controller
+ (TDC) to offer the basic capabilities of the hardware to the telephony
+ framework
+ -->
+ <!-- an array of "[hardware type],[hardware-uuid],[state],[[hardware-type specific]]"
+ with, [[hardware-type specific]] in:
+ - "[[ril-model],[rat],[max-active-voice],[max-active-data],[max-active-standby]]"
+ for 'modem' hardware
+ - "[[associated-modem-uuid]]"
+ for 'sim' hardware.
+ refer to HardwareConfig in com.android.internal.telephony for specific details/values
+ those elements can carry.
+ -->
+ <string-array translatable="false" name="config_telephonyHardware">
+ <!-- modem -->
+ <item>"0,modem,0,0,0,1,1,1"</item>
+ <!-- sim -->
+ <item>"1,sim,0,modem"</item>
+ </string-array>
+
+
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 657f614..e94b9dd 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -365,7 +365,7 @@
<!-- width of ImmersiveModeConfirmation (-1 for match_parent) -->
<dimen name="immersive_mode_cling_width">-1px</dimen>
- <!-- radius of the corners of the quantum rounded rect background -->
- <dimen name="notification_quantum_rounded_rect_radius">2dp</dimen>
+ <!-- radius of the corners of the material rounded rect background -->
+ <dimen name="notification_material_rounded_rect_radius">2dp</dimen>
</resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
new file mode 100644
index 0000000..18e4574
--- /dev/null
+++ b/core/res/res/values/dimens_material.xml
@@ -0,0 +1,63 @@
+<?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.
+-->
+<resources>
+
+ <!-- Preference fragment padding, sides -->
+ <dimen name="preference_fragment_padding_side_material">0dp</dimen>
+
+ <dimen name="preference_screen_header_padding_side_material">0dp</dimen>
+
+ <!-- Default height of an action bar. -->
+ <dimen name="action_bar_default_height_material">56dp</dimen>
+ <!-- Default padding of an action bar. -->
+ <dimen name="action_bar_default_padding_material">4dp</dimen>
+ <!-- Vertical padding around action bar icons. -->
+ <dimen name="action_bar_icon_vertical_padding_material">16dp</dimen>
+ <!-- Top margin for action bar subtitles -->
+ <dimen name="action_bar_subtitle_top_margin_material">-3dp</dimen>
+ <!-- Bottom margin for action bar subtitles -->
+ <dimen name="action_bar_subtitle_bottom_margin_material">5dp</dimen>
+
+ <dimen name="action_button_min_width_material">48dp</dimen>
+ <dimen name="action_button_min_height_material">48dp</dimen>
+ <dimen name="action_overflow_min_width_material">36dp</dimen>
+
+ <dimen name="text_size_display_4_material">112sp</dimen>
+ <dimen name="text_size_display_3_material">56sp</dimen>
+ <dimen name="text_size_display_2_material">45sp</dimen>
+ <dimen name="text_size_display_1_material">34sp</dimen>
+ <dimen name="text_size_headline_material">24sp</dimen>
+ <dimen name="text_size_title_material">20sp</dimen>
+ <dimen name="text_size_subhead_material">16sp</dimen>
+ <dimen name="text_size_body_2_material">14sp</dimen>
+ <dimen name="text_size_body_1_material">14sp</dimen>
+ <dimen name="text_size_caption_material">12sp</dimen>
+ <dimen name="text_size_menu_material">14sp</dimen>
+ <dimen name="text_size_button_material">14sp</dimen>
+
+ <dimen name="text_size_large_material">22sp</dimen>
+ <dimen name="text_size_medium_material">18sp</dimen>
+ <dimen name="text_size_small_material">14sp</dimen>
+
+ <dimen name="floating_window_z">16dp</dimen>
+ <dimen name="floating_window_margin_left">16dp</dimen>
+ <dimen name="floating_window_margin_top">8dp</dimen>
+ <dimen name="floating_window_margin_right">16dp</dimen>
+ <dimen name="floating_window_margin_bottom">32dp</dimen>
+
+ <!-- Amount of elevation for pressed button state -->
+ <dimen name="button_pressed_z">2dp</dimen>
+</resources>
diff --git a/core/res/res/values/dimens_quantum.xml b/core/res/res/values/dimens_quantum.xml
deleted file mode 100644
index 6390667..0000000
--- a/core/res/res/values/dimens_quantum.xml
+++ /dev/null
@@ -1,58 +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.
--->
-<resources>
-
- <!-- Default height of an action bar. -->
- <dimen name="action_bar_default_height_quantum">56dp</dimen>
- <!-- Default padding of an action bar. -->
- <dimen name="action_bar_default_padding_quantum">4dp</dimen>
- <!-- Vertical padding around action bar icons. -->
- <dimen name="action_bar_icon_vertical_padding_quantum">16dp</dimen>
- <!-- Top margin for action bar subtitles -->
- <dimen name="action_bar_subtitle_top_margin_quantum">-3dp</dimen>
- <!-- Bottom margin for action bar subtitles -->
- <dimen name="action_bar_subtitle_bottom_margin_quantum">5dp</dimen>
-
- <dimen name="action_button_min_width_quantum">48dp</dimen>
- <dimen name="action_button_min_height_quantum">48dp</dimen>
- <dimen name="action_overflow_min_width_quantum">36dp</dimen>
-
- <dimen name="text_size_display_4_quantum">112sp</dimen>
- <dimen name="text_size_display_3_quantum">56sp</dimen>
- <dimen name="text_size_display_2_quantum">45sp</dimen>
- <dimen name="text_size_display_1_quantum">34sp</dimen>
- <dimen name="text_size_headline_quantum">24sp</dimen>
- <dimen name="text_size_title_quantum">20sp</dimen>
- <dimen name="text_size_subhead_quantum">16sp</dimen>
- <dimen name="text_size_body_2_quantum">14sp</dimen>
- <dimen name="text_size_body_1_quantum">14sp</dimen>
- <dimen name="text_size_caption_quantum">12sp</dimen>
- <dimen name="text_size_menu_quantum">14sp</dimen>
- <dimen name="text_size_button_quantum">14sp</dimen>
-
- <dimen name="text_size_large_quantum">22sp</dimen>
- <dimen name="text_size_medium_quantum">18sp</dimen>
- <dimen name="text_size_small_quantum">14sp</dimen>
-
- <dimen name="floating_window_z">16dp</dimen>
- <dimen name="floating_window_margin_left">16dp</dimen>
- <dimen name="floating_window_margin_top">8dp</dimen>
- <dimen name="floating_window_margin_right">16dp</dimen>
- <dimen name="floating_window_margin_bottom">32dp</dimen>
-
- <!-- Amount of elevation for pressed button state -->
- <dimen name="button_pressed_z">2dp</dimen>
-</resources>
diff --git a/core/res/res/values/donottranslate_material.xml b/core/res/res/values/donottranslate_material.xml
new file mode 100644
index 0000000..9ed9553
--- /dev/null
+++ b/core/res/res/values/donottranslate_material.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<resources>
+
+ <string name="font_family_display_4_material">sans-serif-light</string>
+ <string name="font_family_display_3_material">sans-serif</string>
+ <string name="font_family_display_2_material">sans-serif</string>
+ <string name="font_family_display_1_material">sans-serif</string>
+ <string name="font_family_headline_material">sans-serif</string>
+ <string name="font_family_title_material">sans-serif-medium</string>
+ <string name="font_family_subhead_material">sans-serif</string>
+ <string name="font_family_body_2_material">sans-serif-medium</string>
+ <string name="font_family_body_1_material">sans-serif</string>
+ <string name="font_family_caption_material">sans-serif</string>
+ <string name="font_family_menu_material">sans-serif-medium</string>
+ <string name="font_family_button_material">sans-serif-medium</string>
+
+</resources>
diff --git a/core/res/res/values/donottranslate_quantum.xml b/core/res/res/values/donottranslate_quantum.xml
deleted file mode 100644
index e53c40e..0000000
--- a/core/res/res/values/donottranslate_quantum.xml
+++ /dev/null
@@ -1,32 +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.
--->
-
-<resources>
-
- <string name="font_family_display_4_quantum">sans-serif-light</string>
- <string name="font_family_display_3_quantum">sans-serif</string>
- <string name="font_family_display_2_quantum">sans-serif</string>
- <string name="font_family_display_1_quantum">sans-serif</string>
- <string name="font_family_headline_quantum">sans-serif</string>
- <string name="font_family_title_quantum">sans-serif-medium</string>
- <string name="font_family_subhead_quantum">sans-serif</string>
- <string name="font_family_body_2_quantum">sans-serif-medium</string>
- <string name="font_family_body_1_quantum">sans-serif</string>
- <string name="font_family_caption_quantum">sans-serif</string>
- <string name="font_family_menu_quantum">sans-serif-medium</string>
- <string name="font_family_button_quantum">sans-serif-medium</string>
-
-</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e048c68..1580d69 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2097,6 +2097,7 @@
<public type="attr" name="isGame" id="0x10103f4" />
<public type="attr" name="allowEmbedded" id="0x10103f5" />
<public type="attr" name="setupActivity" id="0x10103f6"/>
+ <public type="attr" name="tvInputType" id="0x10103f7"/>
<!-- ===============================================================
Resources added in version 21 of the platform
@@ -2131,7 +2132,6 @@
<public type="attr" name="strokeLineJoin" />
<public type="attr" name="clipToPath" />
<public type="attr" name="requiredForProfile"/>
- <public type="attr" name="pinned" />
<public type="attr" name="colorControlNormal" />
<public type="attr" name="colorControlActivated" />
<public type="attr" name="colorButtonNormal" />
@@ -2161,6 +2161,7 @@
<public type="attr" name="hideOnContentScroll" />
<public type="attr" name="actionOverflowMenuStyle" />
<public type="attr" name="documentLaunchMode" />
+ <public type="attr" name="maxRecents" />
<public type="attr" name="autoRemoveFromRecents" />
<public type="attr" name="stateListAnimator" />
<public type="attr" name="toId" />
@@ -2184,6 +2185,27 @@
<public type="attr" name="translateY" />
<public type="attr" name="selectableItemBackgroundBorderless" />
<public type="attr" name="elegantTextHeight" />
+ <public type="attr" name="searchKeyphraseId" />
+ <public type="attr" name="searchKeyphrase" />
+ <public type="attr" name="searchKeyphraseSupportedLocales" />
+ <public type="attr" name="windowTransitionBackgroundFadeDuration" />
+ <public type="attr" name="overlapAnchor" />
+ <public type="attr" name="progressTint" />
+ <public type="attr" name="progressTintMode" />
+ <public type="attr" name="progressBackgroundTint" />
+ <public type="attr" name="progressBackgroundTintMode" />
+ <public type="attr" name="secondaryProgressTint" />
+ <public type="attr" name="secondaryProgressTintMode" />
+ <public type="attr" name="indeterminateTint" />
+ <public type="attr" name="indeterminateTintMode" />
+ <public type="attr" name="backgroundTint" />
+ <public type="attr" name="backgroundTintMode" />
+ <public type="attr" name="foregroundTint" />
+ <public type="attr" name="foregroundTintMode" />
+ <public type="attr" name="buttonTint" />
+ <public type="attr" name="buttonTintMode" />
+ <public type="attr" name="thumbTint" />
+ <public type="attr" name="thumbTintMode" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
@@ -2195,6 +2217,8 @@
<public type="style" name="Widget.FastScroll" />
<public type="style" name="Widget.StackView" />
+ <public type="style" name="Widget.Toolbar" />
+ <public type="style" name="Widget.Toolbar.Button.Navigation" />
<public type="style" name="Widget.Holo.FastScroll" />
<public type="style" name="Widget.Holo.StackView" />
@@ -2209,215 +2233,220 @@
<public type="style" name="Widget.DeviceDefault.Light.FastScroll" />
<public type="style" name="Widget.DeviceDefault.Light.StackView" />
- <public type="style" name="TextAppearance.Quantum" />
- <public type="style" name="TextAppearance.Quantum.DialogWindowTitle" />
- <public type="style" name="TextAppearance.Quantum.Inverse" />
- <public type="style" name="TextAppearance.Quantum.Large" />
- <public type="style" name="TextAppearance.Quantum.Large.Inverse" />
- <public type="style" name="TextAppearance.Quantum.Medium" />
- <public type="style" name="TextAppearance.Quantum.Medium.Inverse" />
- <public type="style" name="TextAppearance.Quantum.SearchResult.Subtitle" />
- <public type="style" name="TextAppearance.Quantum.SearchResult.Title" />
- <public type="style" name="TextAppearance.Quantum.Small" />
- <public type="style" name="TextAppearance.Quantum.Small.Inverse" />
- <public type="style" name="TextAppearance.Quantum.WindowTitle" />
+ <public type="style" name="TextAppearance.Material" />
+ <public type="style" name="TextAppearance.Material.DialogWindowTitle" />
+ <public type="style" name="TextAppearance.Material.Inverse" />
+ <public type="style" name="TextAppearance.Material.Large" />
+ <public type="style" name="TextAppearance.Material.Large.Inverse" />
+ <public type="style" name="TextAppearance.Material.Medium" />
+ <public type="style" name="TextAppearance.Material.Medium.Inverse" />
+ <public type="style" name="TextAppearance.Material.SearchResult.Subtitle" />
+ <public type="style" name="TextAppearance.Material.SearchResult.Title" />
+ <public type="style" name="TextAppearance.Material.Small" />
+ <public type="style" name="TextAppearance.Material.Small.Inverse" />
+ <public type="style" name="TextAppearance.Material.WindowTitle" />
- <public type="style" name="TextAppearance.Quantum.Widget" />
- <public type="style" name="TextAppearance.Quantum.Widget.ActionBar.Menu" />
- <public type="style" name="TextAppearance.Quantum.Widget.ActionBar.Subtitle" />
- <public type="style" name="TextAppearance.Quantum.Widget.ActionBar.Subtitle.Inverse" />
- <public type="style" name="TextAppearance.Quantum.Widget.ActionBar.Title" />
- <public type="style" name="TextAppearance.Quantum.Widget.ActionBar.Title.Inverse" />
- <public type="style" name="TextAppearance.Quantum.Widget.ActionMode.Subtitle" />
- <public type="style" name="TextAppearance.Quantum.Widget.ActionMode.Subtitle.Inverse" />
- <public type="style" name="TextAppearance.Quantum.Widget.ActionMode.Title" />
- <public type="style" name="TextAppearance.Quantum.Widget.ActionMode.Title.Inverse" />
- <public type="style" name="TextAppearance.Quantum.Widget.Button" />
- <public type="style" name="TextAppearance.Quantum.Widget.DropDownHint" />
- <public type="style" name="TextAppearance.Quantum.Widget.DropDownItem" />
- <public type="style" name="TextAppearance.Quantum.Widget.EditText" />
- <public type="style" name="TextAppearance.Quantum.Widget.IconMenu.Item" />
- <public type="style" name="TextAppearance.Quantum.Widget.PopupMenu" />
- <public type="style" name="TextAppearance.Quantum.Widget.PopupMenu.Large" />
- <public type="style" name="TextAppearance.Quantum.Widget.PopupMenu.Small" />
- <public type="style" name="TextAppearance.Quantum.Widget.TabWidget" />
- <public type="style" name="TextAppearance.Quantum.Widget.TextView" />
- <public type="style" name="TextAppearance.Quantum.Widget.TextView.PopupMenu" />
- <public type="style" name="TextAppearance.Quantum.Widget.TextView.SpinnerItem" />
+ <public type="style" name="TextAppearance.Material.Widget" />
+ <public type="style" name="TextAppearance.Material.Widget.ActionBar.Menu" />
+ <public type="style" name="TextAppearance.Material.Widget.ActionBar.Subtitle" />
+ <public type="style" name="TextAppearance.Material.Widget.ActionBar.Subtitle.Inverse" />
+ <public type="style" name="TextAppearance.Material.Widget.ActionBar.Title" />
+ <public type="style" name="TextAppearance.Material.Widget.ActionBar.Title.Inverse" />
+ <public type="style" name="TextAppearance.Material.Widget.ActionMode.Subtitle" />
+ <public type="style" name="TextAppearance.Material.Widget.ActionMode.Subtitle.Inverse" />
+ <public type="style" name="TextAppearance.Material.Widget.ActionMode.Title" />
+ <public type="style" name="TextAppearance.Material.Widget.ActionMode.Title.Inverse" />
+ <public type="style" name="TextAppearance.Material.Widget.Button" />
+ <public type="style" name="TextAppearance.Material.Widget.DropDownHint" />
+ <public type="style" name="TextAppearance.Material.Widget.DropDownItem" />
+ <public type="style" name="TextAppearance.Material.Widget.EditText" />
+ <public type="style" name="TextAppearance.Material.Widget.IconMenu.Item" />
+ <public type="style" name="TextAppearance.Material.Widget.PopupMenu" />
+ <public type="style" name="TextAppearance.Material.Widget.PopupMenu.Large" />
+ <public type="style" name="TextAppearance.Material.Widget.PopupMenu.Small" />
+ <public type="style" name="TextAppearance.Material.Widget.TabWidget" />
+ <public type="style" name="TextAppearance.Material.Widget.TextView" />
+ <public type="style" name="TextAppearance.Material.Widget.TextView.PopupMenu" />
+ <public type="style" name="TextAppearance.Material.Widget.TextView.SpinnerItem" />
- <public type="style" name="Theme.Quantum" />
- <public type="style" name="Theme.Quantum.Dialog" />
- <public type="style" name="Theme.Quantum.Dialog.MinWidth" />
- <public type="style" name="Theme.Quantum.Dialog.NoActionBar" />
- <public type="style" name="Theme.Quantum.Dialog.NoActionBar.MinWidth" />
- <public type="style" name="Theme.Quantum.DialogWhenLarge" />
- <public type="style" name="Theme.Quantum.DialogWhenLarge.NoActionBar" />
- <public type="style" name="Theme.Quantum.InputMethod" />
- <public type="style" name="Theme.Quantum.NoActionBar" />
- <public type="style" name="Theme.Quantum.NoActionBar.Fullscreen" />
- <public type="style" name="Theme.Quantum.NoActionBar.Overscan" />
- <public type="style" name="Theme.Quantum.NoActionBar.TranslucentDecor" />
- <public type="style" name="Theme.Quantum.Panel" />
- <public type="style" name="Theme.Quantum.Voice" />
- <public type="style" name="Theme.Quantum.Wallpaper" />
- <public type="style" name="Theme.Quantum.Wallpaper.NoTitleBar" />
+ <public type="style" name="Theme.DeviceDefault.Settings" />
- <public type="style" name="Theme.Quantum.Light" />
- <public type="style" name="Theme.Quantum.Light.DarkActionBar" />
- <public type="style" name="Theme.Quantum.Light.Dialog" />
- <public type="style" name="Theme.Quantum.Light.Dialog.MinWidth" />
- <public type="style" name="Theme.Quantum.Light.Dialog.NoActionBar" />
- <public type="style" name="Theme.Quantum.Light.Dialog.NoActionBar.MinWidth" />
- <public type="style" name="Theme.Quantum.Light.DialogWhenLarge" />
- <public type="style" name="Theme.Quantum.Light.DialogWhenLarge.NoActionBar" />
- <public type="style" name="Theme.Quantum.Light.NoActionBar" />
- <public type="style" name="Theme.Quantum.Light.NoActionBar.Fullscreen" />
- <public type="style" name="Theme.Quantum.Light.NoActionBar.Overscan" />
- <public type="style" name="Theme.Quantum.Light.NoActionBar.TranslucentDecor" />
- <public type="style" name="Theme.Quantum.Light.Panel" />
- <public type="style" name="Theme.Quantum.Light.Voice" />
+ <public type="style" name="Theme.Material" />
+ <public type="style" name="Theme.Material.Dialog" />
+ <public type="style" name="Theme.Material.Dialog.MinWidth" />
+ <public type="style" name="Theme.Material.Dialog.NoActionBar" />
+ <public type="style" name="Theme.Material.Dialog.NoActionBar.MinWidth" />
+ <public type="style" name="Theme.Material.DialogWhenLarge" />
+ <public type="style" name="Theme.Material.DialogWhenLarge.NoActionBar" />
+ <public type="style" name="Theme.Material.InputMethod" />
+ <public type="style" name="Theme.Material.NoActionBar" />
+ <public type="style" name="Theme.Material.NoActionBar.Fullscreen" />
+ <public type="style" name="Theme.Material.NoActionBar.Overscan" />
+ <public type="style" name="Theme.Material.NoActionBar.TranslucentDecor" />
+ <public type="style" name="Theme.Material.Panel" />
+ <public type="style" name="Theme.Material.Settings" />
+ <public type="style" name="Theme.Material.Voice" />
+ <public type="style" name="Theme.Material.Wallpaper" />
+ <public type="style" name="Theme.Material.Wallpaper.NoTitleBar" />
+
+ <public type="style" name="Theme.Material.Light" />
+ <public type="style" name="Theme.Material.Light.DarkActionBar" />
+ <public type="style" name="Theme.Material.Light.Dialog" />
+ <public type="style" name="Theme.Material.Light.Dialog.MinWidth" />
+ <public type="style" name="Theme.Material.Light.Dialog.NoActionBar" />
+ <public type="style" name="Theme.Material.Light.Dialog.NoActionBar.MinWidth" />
+ <public type="style" name="Theme.Material.Light.DialogWhenLarge" />
+ <public type="style" name="Theme.Material.Light.DialogWhenLarge.NoActionBar" />
+ <public type="style" name="Theme.Material.Light.NoActionBar" />
+ <public type="style" name="Theme.Material.Light.NoActionBar.Fullscreen" />
+ <public type="style" name="Theme.Material.Light.NoActionBar.Overscan" />
+ <public type="style" name="Theme.Material.Light.NoActionBar.TranslucentDecor" />
+ <public type="style" name="Theme.Material.Light.Panel" />
+ <public type="style" name="Theme.Material.Light.Voice" />
<public type="style" name="ThemeOverlay" />
- <public type="style" name="ThemeOverlay.Quantum" />
- <public type="style" name="ThemeOverlay.Quantum.ActionBar" />
- <public type="style" name="ThemeOverlay.Quantum.Light" />
- <public type="style" name="ThemeOverlay.Quantum.Dark" />
- <public type="style" name="ThemeOverlay.Quantum.Dark.ActionBar" />
+ <public type="style" name="ThemeOverlay.Material" />
+ <public type="style" name="ThemeOverlay.Material.ActionBar" />
+ <public type="style" name="ThemeOverlay.Material.Light" />
+ <public type="style" name="ThemeOverlay.Material.Dark" />
+ <public type="style" name="ThemeOverlay.Material.Dark.ActionBar" />
- <public type="style" name="Widget.Quantum" />
- <public type="style" name="Widget.Quantum.ActionBar" />
- <public type="style" name="Widget.Quantum.ActionBar.Solid" />
- <public type="style" name="Widget.Quantum.ActionBar.TabBar" />
- <public type="style" name="Widget.Quantum.ActionBar.TabText" />
- <public type="style" name="Widget.Quantum.ActionBar.TabView" />
- <public type="style" name="Widget.Quantum.ActionButton" />
- <public type="style" name="Widget.Quantum.ActionButton.CloseMode" />
- <public type="style" name="Widget.Quantum.ActionButton.Overflow" />
- <public type="style" name="Widget.Quantum.ActionMode" />
- <public type="style" name="Widget.Quantum.AutoCompleteTextView" />
- <public type="style" name="Widget.Quantum.Button" />
- <public type="style" name="Widget.Quantum.Button.Borderless" />
- <public type="style" name="Widget.Quantum.Button.Borderless.Small" />
- <public type="style" name="Widget.Quantum.Button.Inset" />
- <public type="style" name="Widget.Quantum.Button.Small" />
- <public type="style" name="Widget.Quantum.Button.Toggle" />
- <public type="style" name="Widget.Quantum.ButtonBar" />
- <public type="style" name="Widget.Quantum.ButtonBar.AlertDialog" />
- <public type="style" name="Widget.Quantum.CalendarView" />
- <public type="style" name="Widget.Quantum.CheckedTextView" />
- <public type="style" name="Widget.Quantum.CompoundButton.CheckBox" />
- <public type="style" name="Widget.Quantum.CompoundButton.RadioButton" />
- <public type="style" name="Widget.Quantum.CompoundButton.Star" />
- <public type="style" name="Widget.Quantum.DatePicker" />
- <public type="style" name="Widget.Quantum.DropDownItem" />
- <public type="style" name="Widget.Quantum.DropDownItem.Spinner" />
- <public type="style" name="Widget.Quantum.EditText" />
- <public type="style" name="Widget.Quantum.ExpandableListView" />
- <public type="style" name="Widget.Quantum.FastScroll" />
- <public type="style" name="Widget.Quantum.GridView" />
- <public type="style" name="Widget.Quantum.HorizontalScrollView" />
- <public type="style" name="Widget.Quantum.ImageButton" />
- <public type="style" name="Widget.Quantum.ListPopupWindow" />
- <public type="style" name="Widget.Quantum.ListView" />
- <public type="style" name="Widget.Quantum.ListView.DropDown" />
- <public type="style" name="Widget.Quantum.MediaRouteButton" />
- <public type="style" name="Widget.Quantum.PopupMenu" />
- <public type="style" name="Widget.Quantum.PopupMenu.Overflow" />
- <public type="style" name="Widget.Quantum.PopupWindow" />
- <public type="style" name="Widget.Quantum.ProgressBar" />
- <public type="style" name="Widget.Quantum.ProgressBar.Horizontal" />
- <public type="style" name="Widget.Quantum.ProgressBar.Large" />
- <public type="style" name="Widget.Quantum.ProgressBar.Small" />
- <public type="style" name="Widget.Quantum.ProgressBar.Small.Title" />
- <public type="style" name="Widget.Quantum.RatingBar" />
- <public type="style" name="Widget.Quantum.RatingBar.Indicator" />
- <public type="style" name="Widget.Quantum.RatingBar.Small" />
- <public type="style" name="Widget.Quantum.ScrollView" />
- <public type="style" name="Widget.Quantum.SeekBar" />
- <public type="style" name="Widget.Quantum.SegmentedButton" />
- <public type="style" name="Widget.Quantum.StackView" />
- <public type="style" name="Widget.Quantum.Spinner" />
- <public type="style" name="Widget.Quantum.Tab" />
- <public type="style" name="Widget.Quantum.TabWidget" />
- <public type="style" name="Widget.Quantum.TextView" />
- <public type="style" name="Widget.Quantum.TextView.SpinnerItem" />
- <public type="style" name="Widget.Quantum.WebTextView" />
- <public type="style" name="Widget.Quantum.WebView" />
+ <public type="style" name="Widget.Material" />
+ <public type="style" name="Widget.Material.ActionBar" />
+ <public type="style" name="Widget.Material.ActionBar.Solid" />
+ <public type="style" name="Widget.Material.ActionBar.TabBar" />
+ <public type="style" name="Widget.Material.ActionBar.TabText" />
+ <public type="style" name="Widget.Material.ActionBar.TabView" />
+ <public type="style" name="Widget.Material.ActionButton" />
+ <public type="style" name="Widget.Material.ActionButton.CloseMode" />
+ <public type="style" name="Widget.Material.ActionButton.Overflow" />
+ <public type="style" name="Widget.Material.ActionMode" />
+ <public type="style" name="Widget.Material.AutoCompleteTextView" />
+ <public type="style" name="Widget.Material.Button" />
+ <public type="style" name="Widget.Material.Button.Borderless" />
+ <public type="style" name="Widget.Material.Button.Borderless.Small" />
+ <public type="style" name="Widget.Material.Button.Inset" />
+ <public type="style" name="Widget.Material.Button.Small" />
+ <public type="style" name="Widget.Material.Button.Toggle" />
+ <public type="style" name="Widget.Material.ButtonBar" />
+ <public type="style" name="Widget.Material.ButtonBar.AlertDialog" />
+ <public type="style" name="Widget.Material.CalendarView" />
+ <public type="style" name="Widget.Material.CheckedTextView" />
+ <public type="style" name="Widget.Material.CompoundButton.CheckBox" />
+ <public type="style" name="Widget.Material.CompoundButton.RadioButton" />
+ <public type="style" name="Widget.Material.CompoundButton.Star" />
+ <public type="style" name="Widget.Material.DatePicker" />
+ <public type="style" name="Widget.Material.DropDownItem" />
+ <public type="style" name="Widget.Material.DropDownItem.Spinner" />
+ <public type="style" name="Widget.Material.EditText" />
+ <public type="style" name="Widget.Material.ExpandableListView" />
+ <public type="style" name="Widget.Material.FastScroll" />
+ <public type="style" name="Widget.Material.GridView" />
+ <public type="style" name="Widget.Material.HorizontalScrollView" />
+ <public type="style" name="Widget.Material.ImageButton" />
+ <public type="style" name="Widget.Material.ListPopupWindow" />
+ <public type="style" name="Widget.Material.ListView" />
+ <public type="style" name="Widget.Material.ListView.DropDown" />
+ <public type="style" name="Widget.Material.MediaRouteButton" />
+ <public type="style" name="Widget.Material.PopupMenu" />
+ <public type="style" name="Widget.Material.PopupMenu.Overflow" />
+ <public type="style" name="Widget.Material.PopupWindow" />
+ <public type="style" name="Widget.Material.ProgressBar" />
+ <public type="style" name="Widget.Material.ProgressBar.Horizontal" />
+ <public type="style" name="Widget.Material.ProgressBar.Large" />
+ <public type="style" name="Widget.Material.ProgressBar.Small" />
+ <public type="style" name="Widget.Material.ProgressBar.Small.Title" />
+ <public type="style" name="Widget.Material.RatingBar" />
+ <public type="style" name="Widget.Material.RatingBar.Indicator" />
+ <public type="style" name="Widget.Material.RatingBar.Small" />
+ <public type="style" name="Widget.Material.ScrollView" />
+ <public type="style" name="Widget.Material.SeekBar" />
+ <public type="style" name="Widget.Material.SegmentedButton" />
+ <public type="style" name="Widget.Material.StackView" />
+ <public type="style" name="Widget.Material.Spinner" />
+ <public type="style" name="Widget.Material.Tab" />
+ <public type="style" name="Widget.Material.TabWidget" />
+ <public type="style" name="Widget.Material.TextView" />
+ <public type="style" name="Widget.Material.TextView.SpinnerItem" />
+ <public type="style" name="Widget.Material.Toolbar" />
+ <public type="style" name="Widget.Material.Toolbar.Button.Navigation" />
+ <public type="style" name="Widget.Material.WebTextView" />
+ <public type="style" name="Widget.Material.WebView" />
- <public type="style" name="Widget.Quantum.Light" />
- <public type="style" name="Widget.Quantum.Light.ActionBar" />
- <public type="style" name="Widget.Quantum.Light.ActionBar.Solid" />
- <public type="style" name="Widget.Quantum.Light.ActionBar.TabBar" />
- <public type="style" name="Widget.Quantum.Light.ActionBar.TabText" />
- <public type="style" name="Widget.Quantum.Light.ActionBar.TabView" />
- <public type="style" name="Widget.Quantum.Light.ActionButton" />
- <public type="style" name="Widget.Quantum.Light.ActionButton.CloseMode" />
- <public type="style" name="Widget.Quantum.Light.ActionButton.Overflow" />
- <public type="style" name="Widget.Quantum.Light.ActionMode" />
- <public type="style" name="Widget.Quantum.Light.AutoCompleteTextView" />
- <public type="style" name="Widget.Quantum.Light.Button" />
- <public type="style" name="Widget.Quantum.Light.Button.Borderless" />
- <public type="style" name="Widget.Quantum.Light.Button.Borderless.Small" />
- <public type="style" name="Widget.Quantum.Light.Button.Inset" />
- <public type="style" name="Widget.Quantum.Light.Button.Small" />
- <public type="style" name="Widget.Quantum.Light.Button.Toggle" />
- <public type="style" name="Widget.Quantum.Light.ButtonBar" />
- <public type="style" name="Widget.Quantum.Light.ButtonBar.AlertDialog" />
- <public type="style" name="Widget.Quantum.Light.CalendarView" />
- <public type="style" name="Widget.Quantum.Light.CheckedTextView" />
- <public type="style" name="Widget.Quantum.Light.CompoundButton.CheckBox" />
- <public type="style" name="Widget.Quantum.Light.CompoundButton.RadioButton" />
- <public type="style" name="Widget.Quantum.Light.CompoundButton.Star" />
- <public type="style" name="Widget.Quantum.Light.DropDownItem" />
- <public type="style" name="Widget.Quantum.Light.DropDownItem.Spinner" />
- <public type="style" name="Widget.Quantum.Light.EditText" />
- <public type="style" name="Widget.Quantum.Light.ExpandableListView" />
- <public type="style" name="Widget.Quantum.Light.FastScroll" />
- <public type="style" name="Widget.Quantum.Light.GridView" />
- <public type="style" name="Widget.Quantum.Light.HorizontalScrollView" />
- <public type="style" name="Widget.Quantum.Light.ImageButton" />
- <public type="style" name="Widget.Quantum.Light.ListPopupWindow" />
- <public type="style" name="Widget.Quantum.Light.ListView" />
- <public type="style" name="Widget.Quantum.Light.ListView.DropDown" />
- <public type="style" name="Widget.Quantum.Light.MediaRouteButton" />
- <public type="style" name="Widget.Quantum.Light.PopupMenu" />
- <public type="style" name="Widget.Quantum.Light.PopupMenu.Overflow" />
- <public type="style" name="Widget.Quantum.Light.PopupWindow" />
- <public type="style" name="Widget.Quantum.Light.ProgressBar" />
- <public type="style" name="Widget.Quantum.Light.ProgressBar.Horizontal" />
- <public type="style" name="Widget.Quantum.Light.ProgressBar.Inverse" />
- <public type="style" name="Widget.Quantum.Light.ProgressBar.Large" />
- <public type="style" name="Widget.Quantum.Light.ProgressBar.Large.Inverse" />
- <public type="style" name="Widget.Quantum.Light.ProgressBar.Small" />
- <public type="style" name="Widget.Quantum.Light.ProgressBar.Small.Inverse" />
- <public type="style" name="Widget.Quantum.Light.ProgressBar.Small.Title" />
- <public type="style" name="Widget.Quantum.Light.RatingBar" />
- <public type="style" name="Widget.Quantum.Light.RatingBar.Indicator" />
- <public type="style" name="Widget.Quantum.Light.RatingBar.Small" />
- <public type="style" name="Widget.Quantum.Light.ScrollView" />
- <public type="style" name="Widget.Quantum.Light.SeekBar" />
- <public type="style" name="Widget.Quantum.Light.SegmentedButton" />
- <public type="style" name="Widget.Quantum.Light.StackView" />
- <public type="style" name="Widget.Quantum.Light.Spinner" />
- <public type="style" name="Widget.Quantum.Light.Tab" />
- <public type="style" name="Widget.Quantum.Light.TabWidget" />
- <public type="style" name="Widget.Quantum.Light.TextView" />
- <public type="style" name="Widget.Quantum.Light.TextView.SpinnerItem" />
- <public type="style" name="Widget.Quantum.Light.WebTextView" />
- <public type="style" name="Widget.Quantum.Light.WebView" />
+ <public type="style" name="Widget.Material.Light" />
+ <public type="style" name="Widget.Material.Light.ActionBar" />
+ <public type="style" name="Widget.Material.Light.ActionBar.Solid" />
+ <public type="style" name="Widget.Material.Light.ActionBar.TabBar" />
+ <public type="style" name="Widget.Material.Light.ActionBar.TabText" />
+ <public type="style" name="Widget.Material.Light.ActionBar.TabView" />
+ <public type="style" name="Widget.Material.Light.ActionButton" />
+ <public type="style" name="Widget.Material.Light.ActionButton.CloseMode" />
+ <public type="style" name="Widget.Material.Light.ActionButton.Overflow" />
+ <public type="style" name="Widget.Material.Light.ActionMode" />
+ <public type="style" name="Widget.Material.Light.AutoCompleteTextView" />
+ <public type="style" name="Widget.Material.Light.Button" />
+ <public type="style" name="Widget.Material.Light.Button.Borderless" />
+ <public type="style" name="Widget.Material.Light.Button.Borderless.Small" />
+ <public type="style" name="Widget.Material.Light.Button.Inset" />
+ <public type="style" name="Widget.Material.Light.Button.Small" />
+ <public type="style" name="Widget.Material.Light.Button.Toggle" />
+ <public type="style" name="Widget.Material.Light.ButtonBar" />
+ <public type="style" name="Widget.Material.Light.ButtonBar.AlertDialog" />
+ <public type="style" name="Widget.Material.Light.CalendarView" />
+ <public type="style" name="Widget.Material.Light.CheckedTextView" />
+ <public type="style" name="Widget.Material.Light.CompoundButton.CheckBox" />
+ <public type="style" name="Widget.Material.Light.CompoundButton.RadioButton" />
+ <public type="style" name="Widget.Material.Light.CompoundButton.Star" />
+ <public type="style" name="Widget.Material.Light.DropDownItem" />
+ <public type="style" name="Widget.Material.Light.DropDownItem.Spinner" />
+ <public type="style" name="Widget.Material.Light.EditText" />
+ <public type="style" name="Widget.Material.Light.ExpandableListView" />
+ <public type="style" name="Widget.Material.Light.FastScroll" />
+ <public type="style" name="Widget.Material.Light.GridView" />
+ <public type="style" name="Widget.Material.Light.HorizontalScrollView" />
+ <public type="style" name="Widget.Material.Light.ImageButton" />
+ <public type="style" name="Widget.Material.Light.ListPopupWindow" />
+ <public type="style" name="Widget.Material.Light.ListView" />
+ <public type="style" name="Widget.Material.Light.ListView.DropDown" />
+ <public type="style" name="Widget.Material.Light.MediaRouteButton" />
+ <public type="style" name="Widget.Material.Light.PopupMenu" />
+ <public type="style" name="Widget.Material.Light.PopupMenu.Overflow" />
+ <public type="style" name="Widget.Material.Light.PopupWindow" />
+ <public type="style" name="Widget.Material.Light.ProgressBar" />
+ <public type="style" name="Widget.Material.Light.ProgressBar.Horizontal" />
+ <public type="style" name="Widget.Material.Light.ProgressBar.Inverse" />
+ <public type="style" name="Widget.Material.Light.ProgressBar.Large" />
+ <public type="style" name="Widget.Material.Light.ProgressBar.Large.Inverse" />
+ <public type="style" name="Widget.Material.Light.ProgressBar.Small" />
+ <public type="style" name="Widget.Material.Light.ProgressBar.Small.Inverse" />
+ <public type="style" name="Widget.Material.Light.ProgressBar.Small.Title" />
+ <public type="style" name="Widget.Material.Light.RatingBar" />
+ <public type="style" name="Widget.Material.Light.RatingBar.Indicator" />
+ <public type="style" name="Widget.Material.Light.RatingBar.Small" />
+ <public type="style" name="Widget.Material.Light.ScrollView" />
+ <public type="style" name="Widget.Material.Light.SeekBar" />
+ <public type="style" name="Widget.Material.Light.SegmentedButton" />
+ <public type="style" name="Widget.Material.Light.StackView" />
+ <public type="style" name="Widget.Material.Light.Spinner" />
+ <public type="style" name="Widget.Material.Light.Tab" />
+ <public type="style" name="Widget.Material.Light.TabWidget" />
+ <public type="style" name="Widget.Material.Light.TextView" />
+ <public type="style" name="Widget.Material.Light.TextView.SpinnerItem" />
+ <public type="style" name="Widget.Material.Light.WebTextView" />
+ <public type="style" name="Widget.Material.Light.WebView" />
- <public type="style" name="TextAppearance.Quantum.Display4" />
- <public type="style" name="TextAppearance.Quantum.Display3" />
- <public type="style" name="TextAppearance.Quantum.Display2" />
- <public type="style" name="TextAppearance.Quantum.Display1" />
- <public type="style" name="TextAppearance.Quantum.Headline" />
- <public type="style" name="TextAppearance.Quantum.Title" />
- <public type="style" name="TextAppearance.Quantum.Subhead" />
- <public type="style" name="TextAppearance.Quantum.Body2" />
- <public type="style" name="TextAppearance.Quantum.Body1" />
- <public type="style" name="TextAppearance.Quantum.Caption" />
- <public type="style" name="TextAppearance.Quantum.Menu" />
- <public type="style" name="TextAppearance.Quantum.Button" />
+ <public type="style" name="TextAppearance.Material.Display4" />
+ <public type="style" name="TextAppearance.Material.Display3" />
+ <public type="style" name="TextAppearance.Material.Display2" />
+ <public type="style" name="TextAppearance.Material.Display1" />
+ <public type="style" name="TextAppearance.Material.Headline" />
+ <public type="style" name="TextAppearance.Material.Title" />
+ <public type="style" name="TextAppearance.Material.Subhead" />
+ <public type="style" name="TextAppearance.Material.Body2" />
+ <public type="style" name="TextAppearance.Material.Body1" />
+ <public type="style" name="TextAppearance.Material.Caption" />
+ <public type="style" name="TextAppearance.Material.Menu" />
+ <public type="style" name="TextAppearance.Material.Button" />
<public-padding type="interpolator" name="l_resource_pad" end="0x010c0010" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 391a32c..6e1b5ef 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -460,7 +460,7 @@
<string name="user_owner_label">Personal apps</string>
<!-- Label for a corporate profile in the intent forwarding app. -->
- <string name="managed_profile_label">Android for Work</string>
+ <string name="managed_profile_label">Android Work</string>
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_costMoney">Services that cost you money</string>
@@ -1122,6 +1122,12 @@
interface of a voice interaction service. Should never be needed for normal apps.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_manageVoiceKeyphrases">manage voice keyphrases</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_manageVoiceKeyphrases">Allows the holder to manage the keyphrases for voice hotword detection.
+ Should never be needed for normal apps.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_bindRemoteDisplay">bind to a remote display</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_bindRemoteDisplay">Allows the holder to bind to the top-level
@@ -1260,11 +1266,11 @@
<!-- Title of a permission that is never presented to the user. This is not a
permission that an application must be granted by the user. Instead, it
is part of a mechanism that applications use to indicate to the system
- that they want to do occasional work while the device is idle. -->
- <string name="permlab_bindIdleService">run application during idle time</string>
+ that they want to do scheduled background work. -->
+ <string name="permlab_bindJobService">run the application\'s scheduled background work</string>
<!-- Description of an application permission, so that the user can understand
what is being done if they are curious. -->
- <string name="permdesc_bindIdleService">This permission allows the Android system to run the application in the background while the device is not in use.</string>
+ <string name="permdesc_bindJobService">This permission allows the Android system to run the application in the background when requested.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_diagnostic">read/write to resources owned by diag</string>
@@ -3789,6 +3795,8 @@
<string name="permlab_provide_trust_agent">Provide a trust agent.</string>
<!-- Description of an application permission that lets it provide a trust agent. -->
<string name="permdesc_provide_trust_agent">Allows an application to provide a trust agent.</string>
+ <string name="permlab_launch_trust_agent_settings">Lunch trust agent settings menu.</string>
+ <string name="permdesc_launch_trust_agent_settings">Allows an application to lunch an activity that changes the trust agent behavior.</string>
<!-- Title of an application permission that lets it bind to a trust agent service. -->
<string name="permlab_bind_trust_agent_service">Bind to a trust agent service</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 5bd6122..d6be3133 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -980,6 +980,10 @@
<item name="android:switchTextOff">@android:string/capital_off</item>
</style>
+ <style name="Preference.SeekBarPreference">
+ <item name="android:layout">@android:layout/preference_widget_seekbar</item>
+ </style>
+
<style name="Preference.PreferenceScreen">
</style>
@@ -1035,6 +1039,10 @@
<item name="android:switchTextOff">@android:string/capital_off</item>
</style>
+ <style name="Preference.Holo.SeekBarPreference">
+ <item name="android:layout">@android:layout/preference_widget_seekbar</item>
+ </style>
+
<style name="Preference.Holo.PreferenceScreen">
</style>
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 609a0f3..84d38ce 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -32,149 +32,149 @@
-->
<resources>
<!-- Widget Styles -->
- <style name="Widget.DeviceDefault" parent="Widget.Quantum"/>
- <style name="Widget.DeviceDefault.Button" parent="Widget.Quantum.Button"/>
- <style name="Widget.DeviceDefault.Button.Small" parent="Widget.Quantum.Button.Small"/>
- <style name="Widget.DeviceDefault.Button.Inset" parent="Widget.Quantum.Button.Inset"/>
- <style name="Widget.DeviceDefault.Button.Toggle" parent="Widget.Quantum.Button.Toggle"/>
- <style name="Widget.DeviceDefault.TextView" parent="Widget.Quantum.TextView"/>
- <style name="Widget.DeviceDefault.CheckedTextView" parent="Widget.Quantum.CheckedTextView"/>
- <style name="Widget.DeviceDefault.AutoCompleteTextView" parent="Widget.Quantum.AutoCompleteTextView"/>
- <style name="Widget.DeviceDefault.CompoundButton.CheckBox" parent="Widget.Quantum.CompoundButton.CheckBox"/>
- <style name="Widget.DeviceDefault.ListView.DropDown" parent="Widget.Quantum.ListView.DropDown"/>
- <style name="Widget.DeviceDefault.EditText" parent="Widget.Quantum.EditText"/>
- <style name="Widget.DeviceDefault.ExpandableListView" parent="Widget.Quantum.ExpandableListView"/>
- <style name="Widget.DeviceDefault.GridView" parent="Widget.Quantum.GridView"/>
- <style name="Widget.DeviceDefault.ImageButton" parent="Widget.Quantum.ImageButton"/>
- <style name="Widget.DeviceDefault.ListView" parent="Widget.Quantum.ListView"/>
- <style name="Widget.DeviceDefault.PopupWindow" parent="Widget.Quantum.PopupWindow"/>
- <style name="Widget.DeviceDefault.ProgressBar" parent="Widget.Quantum.ProgressBar"/>
- <style name="Widget.DeviceDefault.ProgressBar.Horizontal" parent="Widget.Quantum.ProgressBar.Horizontal"/>
- <style name="Widget.DeviceDefault.ProgressBar.Small" parent="Widget.Quantum.ProgressBar.Small"/>
- <style name="Widget.DeviceDefault.ProgressBar.Small.Title" parent="Widget.Quantum.ProgressBar.Small.Title"/>
- <style name="Widget.DeviceDefault.ProgressBar.Large" parent="Widget.Quantum.ProgressBar.Large"/>
- <style name="Widget.DeviceDefault.SeekBar" parent="Widget.Quantum.SeekBar"/>
- <style name="Widget.DeviceDefault.RatingBar" parent="Widget.Quantum.RatingBar"/>
- <style name="Widget.DeviceDefault.RatingBar.Indicator" parent="Widget.Quantum.RatingBar.Indicator"/>
- <style name="Widget.DeviceDefault.RatingBar.Small" parent="Widget.Quantum.RatingBar.Small"/>
- <style name="Widget.DeviceDefault.CompoundButton.RadioButton" parent="Widget.Quantum.CompoundButton.RadioButton"/>
- <style name="Widget.DeviceDefault.ScrollView" parent="Widget.Quantum.ScrollView"/>
- <style name="Widget.DeviceDefault.HorizontalScrollView" parent="Widget.Quantum.HorizontalScrollView"/>
- <style name="Widget.DeviceDefault.Spinner" parent="Widget.Quantum.Spinner"/>
- <style name="Widget.DeviceDefault.CompoundButton.Star" parent="Widget.Quantum.CompoundButton.Star"/>
- <style name="Widget.DeviceDefault.TabWidget" parent="Widget.Quantum.TabWidget"/>
- <style name="Widget.DeviceDefault.WebTextView" parent="Widget.Quantum.WebTextView"/>
- <style name="Widget.DeviceDefault.WebView" parent="Widget.Quantum.WebView"/>
- <style name="Widget.DeviceDefault.DropDownItem" parent="Widget.Quantum.DropDownItem"/>
- <style name="Widget.DeviceDefault.DropDownItem.Spinner" parent="Widget.Quantum.DropDownItem.Spinner"/>
- <style name="Widget.DeviceDefault.TextView.SpinnerItem" parent="Widget.Quantum.TextView.SpinnerItem"/>
- <style name="Widget.DeviceDefault.ListPopupWindow" parent="Widget.Quantum.ListPopupWindow"/>
- <style name="Widget.DeviceDefault.PopupMenu" parent="Widget.Quantum.PopupMenu"/>
- <style name="Widget.DeviceDefault.ActionButton" parent="Widget.Quantum.ActionButton"/>
- <style name="Widget.DeviceDefault.ActionButton.Overflow" parent="Widget.Quantum.ActionButton.Overflow"/>
- <style name="Widget.DeviceDefault.ActionButton.TextButton" parent="Widget.Quantum.ActionButton"/>
- <style name="Widget.DeviceDefault.ActionMode" parent="Widget.Quantum.ActionMode"/>
- <style name="Widget.DeviceDefault.ActionButton.CloseMode" parent="Widget.Quantum.ActionButton.CloseMode"/>
- <style name="Widget.DeviceDefault.ActionBar" parent="Widget.Quantum.ActionBar"/>
- <style name="Widget.DeviceDefault.Button.Borderless" parent="Widget.Quantum.Button.Borderless"/>
- <style name="Widget.DeviceDefault.Tab" parent="Widget.Quantum.Tab"/>
- <style name="Widget.DeviceDefault.CalendarView" parent="Widget.Quantum.CalendarView"/>
- <style name="Widget.DeviceDefault.DatePicker" parent="Widget.Quantum.DatePicker"/>
- <style name="Widget.DeviceDefault.ActionBar.TabView" parent="Widget.Quantum.ActionBar.TabView"/>
- <style name="Widget.DeviceDefault.ActionBar.TabText" parent="Widget.Quantum.ActionBar.TabText"/>
- <style name="Widget.DeviceDefault.ActionBar.TabBar" parent="Widget.Quantum.ActionBar.TabBar"/>
- <style name="Widget.DeviceDefault.ActionBar.Solid" parent="Widget.Quantum.ActionBar.Solid"/>
- <style name="Widget.DeviceDefault.Button.Borderless.Small" parent="Widget.Quantum.Button.Borderless.Small"/>
- <style name="Widget.DeviceDefault.AbsListView" parent="Widget.Quantum.AbsListView"/>
- <style name="Widget.DeviceDefault.Spinner.DropDown.ActionBar" parent="Widget.Quantum.Spinner.DropDown.ActionBar"/>
- <style name="Widget.DeviceDefault.PopupWindow.ActionMode" parent="Widget.Quantum.PopupWindow.ActionMode"/>
- <style name="Widget.DeviceDefault.CompoundButton.Switch" parent="Widget.Quantum.CompoundButton.Switch"/>
- <style name="Widget.DeviceDefault.ExpandableListView.White" parent="Widget.Quantum.ExpandableListView.White"/>
- <style name="Widget.DeviceDefault.FastScroll" parent="Widget.Quantum.FastScroll"/>
+ <style name="Widget.DeviceDefault" parent="Widget.Material"/>
+ <style name="Widget.DeviceDefault.Button" parent="Widget.Material.Button"/>
+ <style name="Widget.DeviceDefault.Button.Small" parent="Widget.Material.Button.Small"/>
+ <style name="Widget.DeviceDefault.Button.Inset" parent="Widget.Material.Button.Inset"/>
+ <style name="Widget.DeviceDefault.Button.Toggle" parent="Widget.Material.Button.Toggle"/>
+ <style name="Widget.DeviceDefault.TextView" parent="Widget.Material.TextView"/>
+ <style name="Widget.DeviceDefault.CheckedTextView" parent="Widget.Material.CheckedTextView"/>
+ <style name="Widget.DeviceDefault.AutoCompleteTextView" parent="Widget.Material.AutoCompleteTextView"/>
+ <style name="Widget.DeviceDefault.CompoundButton.CheckBox" parent="Widget.Material.CompoundButton.CheckBox"/>
+ <style name="Widget.DeviceDefault.ListView.DropDown" parent="Widget.Material.ListView.DropDown"/>
+ <style name="Widget.DeviceDefault.EditText" parent="Widget.Material.EditText"/>
+ <style name="Widget.DeviceDefault.ExpandableListView" parent="Widget.Material.ExpandableListView"/>
+ <style name="Widget.DeviceDefault.GridView" parent="Widget.Material.GridView"/>
+ <style name="Widget.DeviceDefault.ImageButton" parent="Widget.Material.ImageButton"/>
+ <style name="Widget.DeviceDefault.ListView" parent="Widget.Material.ListView"/>
+ <style name="Widget.DeviceDefault.PopupWindow" parent="Widget.Material.PopupWindow"/>
+ <style name="Widget.DeviceDefault.ProgressBar" parent="Widget.Material.ProgressBar"/>
+ <style name="Widget.DeviceDefault.ProgressBar.Horizontal" parent="Widget.Material.ProgressBar.Horizontal"/>
+ <style name="Widget.DeviceDefault.ProgressBar.Small" parent="Widget.Material.ProgressBar.Small"/>
+ <style name="Widget.DeviceDefault.ProgressBar.Small.Title" parent="Widget.Material.ProgressBar.Small.Title"/>
+ <style name="Widget.DeviceDefault.ProgressBar.Large" parent="Widget.Material.ProgressBar.Large"/>
+ <style name="Widget.DeviceDefault.SeekBar" parent="Widget.Material.SeekBar"/>
+ <style name="Widget.DeviceDefault.RatingBar" parent="Widget.Material.RatingBar"/>
+ <style name="Widget.DeviceDefault.RatingBar.Indicator" parent="Widget.Material.RatingBar.Indicator"/>
+ <style name="Widget.DeviceDefault.RatingBar.Small" parent="Widget.Material.RatingBar.Small"/>
+ <style name="Widget.DeviceDefault.CompoundButton.RadioButton" parent="Widget.Material.CompoundButton.RadioButton"/>
+ <style name="Widget.DeviceDefault.ScrollView" parent="Widget.Material.ScrollView"/>
+ <style name="Widget.DeviceDefault.HorizontalScrollView" parent="Widget.Material.HorizontalScrollView"/>
+ <style name="Widget.DeviceDefault.Spinner" parent="Widget.Material.Spinner"/>
+ <style name="Widget.DeviceDefault.CompoundButton.Star" parent="Widget.Material.CompoundButton.Star"/>
+ <style name="Widget.DeviceDefault.TabWidget" parent="Widget.Material.TabWidget"/>
+ <style name="Widget.DeviceDefault.WebTextView" parent="Widget.Material.WebTextView"/>
+ <style name="Widget.DeviceDefault.WebView" parent="Widget.Material.WebView"/>
+ <style name="Widget.DeviceDefault.DropDownItem" parent="Widget.Material.DropDownItem"/>
+ <style name="Widget.DeviceDefault.DropDownItem.Spinner" parent="Widget.Material.DropDownItem.Spinner"/>
+ <style name="Widget.DeviceDefault.TextView.SpinnerItem" parent="Widget.Material.TextView.SpinnerItem"/>
+ <style name="Widget.DeviceDefault.ListPopupWindow" parent="Widget.Material.ListPopupWindow"/>
+ <style name="Widget.DeviceDefault.PopupMenu" parent="Widget.Material.PopupMenu"/>
+ <style name="Widget.DeviceDefault.ActionButton" parent="Widget.Material.ActionButton"/>
+ <style name="Widget.DeviceDefault.ActionButton.Overflow" parent="Widget.Material.ActionButton.Overflow"/>
+ <style name="Widget.DeviceDefault.ActionButton.TextButton" parent="Widget.Material.ActionButton"/>
+ <style name="Widget.DeviceDefault.ActionMode" parent="Widget.Material.ActionMode"/>
+ <style name="Widget.DeviceDefault.ActionButton.CloseMode" parent="Widget.Material.ActionButton.CloseMode"/>
+ <style name="Widget.DeviceDefault.ActionBar" parent="Widget.Material.ActionBar"/>
+ <style name="Widget.DeviceDefault.Button.Borderless" parent="Widget.Material.Button.Borderless"/>
+ <style name="Widget.DeviceDefault.Tab" parent="Widget.Material.Tab"/>
+ <style name="Widget.DeviceDefault.CalendarView" parent="Widget.Material.CalendarView"/>
+ <style name="Widget.DeviceDefault.DatePicker" parent="Widget.Material.DatePicker"/>
+ <style name="Widget.DeviceDefault.ActionBar.TabView" parent="Widget.Material.ActionBar.TabView"/>
+ <style name="Widget.DeviceDefault.ActionBar.TabText" parent="Widget.Material.ActionBar.TabText"/>
+ <style name="Widget.DeviceDefault.ActionBar.TabBar" parent="Widget.Material.ActionBar.TabBar"/>
+ <style name="Widget.DeviceDefault.ActionBar.Solid" parent="Widget.Material.ActionBar.Solid"/>
+ <style name="Widget.DeviceDefault.Button.Borderless.Small" parent="Widget.Material.Button.Borderless.Small"/>
+ <style name="Widget.DeviceDefault.AbsListView" parent="Widget.Material.AbsListView"/>
+ <style name="Widget.DeviceDefault.Spinner.DropDown.ActionBar" parent="Widget.Material.Spinner.DropDown.ActionBar"/>
+ <style name="Widget.DeviceDefault.PopupWindow.ActionMode" parent="Widget.Material.PopupWindow.ActionMode"/>
+ <style name="Widget.DeviceDefault.CompoundButton.Switch" parent="Widget.Material.CompoundButton.Switch"/>
+ <style name="Widget.DeviceDefault.ExpandableListView.White" parent="Widget.Material.ExpandableListView.White"/>
+ <style name="Widget.DeviceDefault.FastScroll" parent="Widget.Material.FastScroll"/>
<!-- The FragmentBreadCrumbs widget is deprecated starting in API level 21 ({@link android.os.Build.VERSION_CODES#.L}). -->
<style name="Widget.DeviceDefault.FragmentBreadCrumbs" parent="Widget.Holo.FragmentBreadCrumbs"/>
- <style name="Widget.DeviceDefault.Gallery" parent="Widget.Quantum.Gallery"/>
- <style name="Widget.DeviceDefault.GestureOverlayView" parent="Widget.Quantum.GestureOverlayView"/>
- <style name="Widget.DeviceDefault.ImageWell" parent="Widget.Quantum.ImageWell"/>
- <style name="Widget.DeviceDefault.KeyboardView" parent="Widget.Quantum.KeyboardView"/>
- <style name="Widget.DeviceDefault.ListView.White" parent="Widget.Quantum.ListView.White"/>
- <style name="Widget.DeviceDefault.MediaRouteButton" parent="Widget.Quantum.MediaRouteButton" />
- <style name="Widget.DeviceDefault.NumberPicker" parent="Widget.Quantum.NumberPicker"/>
- <style name="Widget.DeviceDefault.PreferenceFrameLayout" parent="Widget.Quantum.PreferenceFrameLayout"/>
- <style name="Widget.DeviceDefault.ProgressBar.Inverse" parent="Widget.Quantum.ProgressBar.Inverse"/>
- <style name="Widget.DeviceDefault.ProgressBar.Large.Inverse" parent="Widget.Quantum.ProgressBar.Large.Inverse"/>
- <style name="Widget.DeviceDefault.ProgressBar.Small.Inverse" parent="Widget.Quantum.ProgressBar.Small.Inverse"/>
- <style name="Widget.DeviceDefault.QuickContactBadge.WindowLarge" parent="Widget.Quantum.QuickContactBadge.WindowLarge"/>
- <style name="Widget.DeviceDefault.QuickContactBadge.WindowMedium" parent="Widget.Quantum.QuickContactBadge.WindowMedium"/>
- <style name="Widget.DeviceDefault.QuickContactBadge.WindowSmall" parent="Widget.Quantum.QuickContactBadge.WindowSmall"/>
- <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge" parent="Widget.Quantum.QuickContactBadgeSmall.WindowLarge"/>
- <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium" parent="Widget.Quantum.QuickContactBadgeSmall.WindowMedium"/>
- <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall" parent="Widget.Quantum.QuickContactBadgeSmall.WindowSmall"/>
- <style name="Widget.DeviceDefault.Spinner.DropDown" parent="Widget.Quantum.Spinner.DropDown"/>
- <style name="Widget.DeviceDefault.StackView" parent="Widget.Quantum.StackView"/>
- <style name="Widget.DeviceDefault.TextSelectHandle" parent="Widget.Quantum.TextSelectHandle"/>
- <style name="Widget.DeviceDefault.TextSuggestionsPopupWindow" parent="Widget.Quantum.TextSuggestionsPopupWindow"/>
- <style name="Widget.DeviceDefault.TextView.ListSeparator" parent="Widget.Quantum.TextView.ListSeparator"/>
- <style name="Widget.DeviceDefault.TimePicker" parent="Widget.Quantum.TimePicker"/>
+ <style name="Widget.DeviceDefault.Gallery" parent="Widget.Material.Gallery"/>
+ <style name="Widget.DeviceDefault.GestureOverlayView" parent="Widget.Material.GestureOverlayView"/>
+ <style name="Widget.DeviceDefault.ImageWell" parent="Widget.Material.ImageWell"/>
+ <style name="Widget.DeviceDefault.KeyboardView" parent="Widget.Material.KeyboardView"/>
+ <style name="Widget.DeviceDefault.ListView.White" parent="Widget.Material.ListView.White"/>
+ <style name="Widget.DeviceDefault.MediaRouteButton" parent="Widget.Material.MediaRouteButton" />
+ <style name="Widget.DeviceDefault.NumberPicker" parent="Widget.Material.NumberPicker"/>
+ <style name="Widget.DeviceDefault.PreferenceFrameLayout" parent="Widget.Material.PreferenceFrameLayout"/>
+ <style name="Widget.DeviceDefault.ProgressBar.Inverse" parent="Widget.Material.ProgressBar.Inverse"/>
+ <style name="Widget.DeviceDefault.ProgressBar.Large.Inverse" parent="Widget.Material.ProgressBar.Large.Inverse"/>
+ <style name="Widget.DeviceDefault.ProgressBar.Small.Inverse" parent="Widget.Material.ProgressBar.Small.Inverse"/>
+ <style name="Widget.DeviceDefault.QuickContactBadge.WindowLarge" parent="Widget.Material.QuickContactBadge.WindowLarge"/>
+ <style name="Widget.DeviceDefault.QuickContactBadge.WindowMedium" parent="Widget.Material.QuickContactBadge.WindowMedium"/>
+ <style name="Widget.DeviceDefault.QuickContactBadge.WindowSmall" parent="Widget.Material.QuickContactBadge.WindowSmall"/>
+ <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge" parent="Widget.Material.QuickContactBadgeSmall.WindowLarge"/>
+ <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium" parent="Widget.Material.QuickContactBadgeSmall.WindowMedium"/>
+ <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall" parent="Widget.Material.QuickContactBadgeSmall.WindowSmall"/>
+ <style name="Widget.DeviceDefault.Spinner.DropDown" parent="Widget.Material.Spinner.DropDown"/>
+ <style name="Widget.DeviceDefault.StackView" parent="Widget.Material.StackView"/>
+ <style name="Widget.DeviceDefault.TextSelectHandle" parent="Widget.Material.TextSelectHandle"/>
+ <style name="Widget.DeviceDefault.TextSuggestionsPopupWindow" parent="Widget.Material.TextSuggestionsPopupWindow"/>
+ <style name="Widget.DeviceDefault.TextView.ListSeparator" parent="Widget.Material.TextView.ListSeparator"/>
+ <style name="Widget.DeviceDefault.TimePicker" parent="Widget.Material.TimePicker"/>
- <style name="Widget.DeviceDefault.Light" parent="Widget.Quantum.Light"/>
- <style name="Widget.DeviceDefault.Light.Button" parent="Widget.Quantum.Light.Button"/>
- <style name="Widget.DeviceDefault.Light.Button.Small" parent="Widget.Quantum.Light.Button.Small"/>
- <style name="Widget.DeviceDefault.Light.Button.Inset" parent="Widget.Quantum.Light.Button.Inset"/>
- <style name="Widget.DeviceDefault.Light.Button.Toggle" parent="Widget.Quantum.Light.Button.Toggle"/>
- <style name="Widget.DeviceDefault.Light.StackView" parent="Widget.Quantum.Light.StackView"/>
- <style name="Widget.DeviceDefault.Light.TextView" parent="Widget.Quantum.Light.TextView"/>
- <style name="Widget.DeviceDefault.Light.CheckedTextView" parent="Widget.Quantum.Light.CheckedTextView"/>
- <style name="Widget.DeviceDefault.Light.AutoCompleteTextView" parent="Widget.Quantum.Light.AutoCompleteTextView"/>
- <style name="Widget.DeviceDefault.Light.CompoundButton.CheckBox" parent="Widget.Quantum.Light.CompoundButton.CheckBox"/>
- <style name="Widget.DeviceDefault.Light.ListView.DropDown" parent="Widget.Quantum.Light.ListView.DropDown"/>
- <style name="Widget.DeviceDefault.Light.EditText" parent="Widget.Quantum.Light.EditText"/>
- <style name="Widget.DeviceDefault.Light.ExpandableListView" parent="Widget.Quantum.Light.ExpandableListView"/>
- <style name="Widget.DeviceDefault.Light.FastScroll" parent="Widget.Quantum.Light.FastScroll"/>
+ <style name="Widget.DeviceDefault.Light" parent="Widget.Material.Light"/>
+ <style name="Widget.DeviceDefault.Light.Button" parent="Widget.Material.Light.Button"/>
+ <style name="Widget.DeviceDefault.Light.Button.Small" parent="Widget.Material.Light.Button.Small"/>
+ <style name="Widget.DeviceDefault.Light.Button.Inset" parent="Widget.Material.Light.Button.Inset"/>
+ <style name="Widget.DeviceDefault.Light.Button.Toggle" parent="Widget.Material.Light.Button.Toggle"/>
+ <style name="Widget.DeviceDefault.Light.StackView" parent="Widget.Material.Light.StackView"/>
+ <style name="Widget.DeviceDefault.Light.TextView" parent="Widget.Material.Light.TextView"/>
+ <style name="Widget.DeviceDefault.Light.CheckedTextView" parent="Widget.Material.Light.CheckedTextView"/>
+ <style name="Widget.DeviceDefault.Light.AutoCompleteTextView" parent="Widget.Material.Light.AutoCompleteTextView"/>
+ <style name="Widget.DeviceDefault.Light.CompoundButton.CheckBox" parent="Widget.Material.Light.CompoundButton.CheckBox"/>
+ <style name="Widget.DeviceDefault.Light.ListView.DropDown" parent="Widget.Material.Light.ListView.DropDown"/>
+ <style name="Widget.DeviceDefault.Light.EditText" parent="Widget.Material.Light.EditText"/>
+ <style name="Widget.DeviceDefault.Light.ExpandableListView" parent="Widget.Material.Light.ExpandableListView"/>
+ <style name="Widget.DeviceDefault.Light.FastScroll" parent="Widget.Material.Light.FastScroll"/>
<!-- The FragmentBreadCrumbs widget is deprecated starting in API level 21 ({@link android.os.Build.VERSION_CODES#.L}). -->
<style name="Widget.DeviceDefault.Light.FragmentBreadCrumbs" parent="Widget.Holo.Light.FragmentBreadCrumbs"/>
- <style name="Widget.DeviceDefault.Light.GridView" parent="Widget.Quantum.Light.GridView"/>
- <style name="Widget.DeviceDefault.Light.ImageButton" parent="Widget.Quantum.Light.ImageButton"/>
- <style name="Widget.DeviceDefault.Light.ListView" parent="Widget.Quantum.Light.ListView"/>
- <style name="Widget.DeviceDefault.Light.MediaRouteButton" parent="Widget.Quantum.Light.MediaRouteButton" />
- <style name="Widget.DeviceDefault.Light.PopupWindow" parent="Widget.Quantum.Light.PopupWindow"/>
- <style name="Widget.DeviceDefault.Light.ProgressBar" parent="Widget.Quantum.Light.ProgressBar"/>
- <style name="Widget.DeviceDefault.Light.ProgressBar.Horizontal" parent="Widget.Quantum.Light.ProgressBar.Horizontal"/>
- <style name="Widget.DeviceDefault.Light.ProgressBar.Small" parent="Widget.Quantum.Light.ProgressBar.Small"/>
- <style name="Widget.DeviceDefault.Light.ProgressBar.Small.Title" parent="Widget.Quantum.Light.ProgressBar.Small.Title"/>
- <style name="Widget.DeviceDefault.Light.ProgressBar.Large" parent="Widget.Quantum.Light.ProgressBar.Large"/>
- <style name="Widget.DeviceDefault.Light.ProgressBar.Inverse" parent="Widget.Quantum.Light.ProgressBar.Inverse"/>
- <style name="Widget.DeviceDefault.Light.ProgressBar.Small.Inverse" parent="Widget.Quantum.Light.ProgressBar.Small.Inverse"/>
- <style name="Widget.DeviceDefault.Light.ProgressBar.Large.Inverse" parent="Widget.Quantum.Light.ProgressBar.Large.Inverse"/>
- <style name="Widget.DeviceDefault.Light.SeekBar" parent="Widget.Quantum.Light.SeekBar"/>
- <style name="Widget.DeviceDefault.Light.RatingBar" parent="Widget.Quantum.Light.RatingBar"/>
- <style name="Widget.DeviceDefault.Light.RatingBar.Indicator" parent="Widget.Quantum.Light.RatingBar.Indicator"/>
- <style name="Widget.DeviceDefault.Light.RatingBar.Small" parent="Widget.Quantum.Light.RatingBar.Small"/>
- <style name="Widget.DeviceDefault.Light.CompoundButton.RadioButton" parent="Widget.Quantum.Light.CompoundButton.RadioButton"/>
- <style name="Widget.DeviceDefault.Light.ScrollView" parent="Widget.Quantum.Light.ScrollView"/>
- <style name="Widget.DeviceDefault.Light.HorizontalScrollView" parent="Widget.Quantum.Light.HorizontalScrollView"/>
- <style name="Widget.DeviceDefault.Light.Spinner" parent="Widget.Quantum.Light.Spinner"/>
- <style name="Widget.DeviceDefault.Light.CompoundButton.Star" parent="Widget.Quantum.Light.CompoundButton.Star"/>
- <style name="Widget.DeviceDefault.Light.TabWidget" parent="Widget.Quantum.Light.TabWidget"/>
- <style name="Widget.DeviceDefault.Light.WebTextView" parent="Widget.Quantum.Light.WebTextView"/>
- <style name="Widget.DeviceDefault.Light.WebView" parent="Widget.Quantum.Light.WebView"/>
- <style name="Widget.DeviceDefault.Light.DropDownItem" parent="Widget.Quantum.Light.DropDownItem"/>
- <style name="Widget.DeviceDefault.Light.DropDownItem.Spinner" parent="Widget.Quantum.Light.DropDownItem.Spinner"/>
- <style name="Widget.DeviceDefault.Light.TextView.SpinnerItem" parent="Widget.Quantum.Light.TextView.SpinnerItem"/>
- <style name="Widget.DeviceDefault.Light.ListPopupWindow" parent="Widget.Quantum.Light.ListPopupWindow"/>
- <style name="Widget.DeviceDefault.Light.PopupMenu" parent="Widget.Quantum.Light.PopupMenu"/>
- <style name="Widget.DeviceDefault.Light.Tab" parent="Widget.Quantum.Light.Tab"/>
- <style name="Widget.DeviceDefault.Light.CalendarView" parent="Widget.Quantum.Light.CalendarView"/>
- <style name="Widget.DeviceDefault.Light.Button.Borderless.Small" parent="Widget.Quantum.Light.Button.Borderless.Small"/>
- <style name="Widget.DeviceDefault.Light.ActionButton" parent="Widget.Quantum.Light.ActionButton"/>
- <style name="Widget.DeviceDefault.Light.ActionButton.Overflow" parent="Widget.Quantum.Light.ActionButton.Overflow"/>
- <style name="Widget.DeviceDefault.Light.ActionMode" parent="Widget.Quantum.Light.ActionMode"/>
- <style name="Widget.DeviceDefault.Light.ActionButton.CloseMode" parent="Widget.Quantum.Light.ActionButton.CloseMode"/>
- <style name="Widget.DeviceDefault.Light.ActionBar" parent="Widget.Quantum.Light.ActionBar"/>
- <style name="Widget.DeviceDefault.Light.ActionBar.TabView" parent="Widget.Quantum.Light.ActionBar.TabView"/>
- <style name="Widget.DeviceDefault.Light.ActionBar.TabText" parent="Widget.Quantum.Light.ActionBar.TabText"/>
- <style name="Widget.DeviceDefault.Light.ActionBar.TabBar" parent="Widget.Quantum.Light.ActionBar.TabBar"/>
- <style name="Widget.DeviceDefault.Light.ActionBar.Solid" parent="Widget.Quantum.Light.ActionBar.Solid"/>
+ <style name="Widget.DeviceDefault.Light.GridView" parent="Widget.Material.Light.GridView"/>
+ <style name="Widget.DeviceDefault.Light.ImageButton" parent="Widget.Material.Light.ImageButton"/>
+ <style name="Widget.DeviceDefault.Light.ListView" parent="Widget.Material.Light.ListView"/>
+ <style name="Widget.DeviceDefault.Light.MediaRouteButton" parent="Widget.Material.Light.MediaRouteButton" />
+ <style name="Widget.DeviceDefault.Light.PopupWindow" parent="Widget.Material.Light.PopupWindow"/>
+ <style name="Widget.DeviceDefault.Light.ProgressBar" parent="Widget.Material.Light.ProgressBar"/>
+ <style name="Widget.DeviceDefault.Light.ProgressBar.Horizontal" parent="Widget.Material.Light.ProgressBar.Horizontal"/>
+ <style name="Widget.DeviceDefault.Light.ProgressBar.Small" parent="Widget.Material.Light.ProgressBar.Small"/>
+ <style name="Widget.DeviceDefault.Light.ProgressBar.Small.Title" parent="Widget.Material.Light.ProgressBar.Small.Title"/>
+ <style name="Widget.DeviceDefault.Light.ProgressBar.Large" parent="Widget.Material.Light.ProgressBar.Large"/>
+ <style name="Widget.DeviceDefault.Light.ProgressBar.Inverse" parent="Widget.Material.Light.ProgressBar.Inverse"/>
+ <style name="Widget.DeviceDefault.Light.ProgressBar.Small.Inverse" parent="Widget.Material.Light.ProgressBar.Small.Inverse"/>
+ <style name="Widget.DeviceDefault.Light.ProgressBar.Large.Inverse" parent="Widget.Material.Light.ProgressBar.Large.Inverse"/>
+ <style name="Widget.DeviceDefault.Light.SeekBar" parent="Widget.Material.Light.SeekBar"/>
+ <style name="Widget.DeviceDefault.Light.RatingBar" parent="Widget.Material.Light.RatingBar"/>
+ <style name="Widget.DeviceDefault.Light.RatingBar.Indicator" parent="Widget.Material.Light.RatingBar.Indicator"/>
+ <style name="Widget.DeviceDefault.Light.RatingBar.Small" parent="Widget.Material.Light.RatingBar.Small"/>
+ <style name="Widget.DeviceDefault.Light.CompoundButton.RadioButton" parent="Widget.Material.Light.CompoundButton.RadioButton"/>
+ <style name="Widget.DeviceDefault.Light.ScrollView" parent="Widget.Material.Light.ScrollView"/>
+ <style name="Widget.DeviceDefault.Light.HorizontalScrollView" parent="Widget.Material.Light.HorizontalScrollView"/>
+ <style name="Widget.DeviceDefault.Light.Spinner" parent="Widget.Material.Light.Spinner"/>
+ <style name="Widget.DeviceDefault.Light.CompoundButton.Star" parent="Widget.Material.Light.CompoundButton.Star"/>
+ <style name="Widget.DeviceDefault.Light.TabWidget" parent="Widget.Material.Light.TabWidget"/>
+ <style name="Widget.DeviceDefault.Light.WebTextView" parent="Widget.Material.Light.WebTextView"/>
+ <style name="Widget.DeviceDefault.Light.WebView" parent="Widget.Material.Light.WebView"/>
+ <style name="Widget.DeviceDefault.Light.DropDownItem" parent="Widget.Material.Light.DropDownItem"/>
+ <style name="Widget.DeviceDefault.Light.DropDownItem.Spinner" parent="Widget.Material.Light.DropDownItem.Spinner"/>
+ <style name="Widget.DeviceDefault.Light.TextView.SpinnerItem" parent="Widget.Material.Light.TextView.SpinnerItem"/>
+ <style name="Widget.DeviceDefault.Light.ListPopupWindow" parent="Widget.Material.Light.ListPopupWindow"/>
+ <style name="Widget.DeviceDefault.Light.PopupMenu" parent="Widget.Material.Light.PopupMenu"/>
+ <style name="Widget.DeviceDefault.Light.Tab" parent="Widget.Material.Light.Tab"/>
+ <style name="Widget.DeviceDefault.Light.CalendarView" parent="Widget.Material.Light.CalendarView"/>
+ <style name="Widget.DeviceDefault.Light.Button.Borderless.Small" parent="Widget.Material.Light.Button.Borderless.Small"/>
+ <style name="Widget.DeviceDefault.Light.ActionButton" parent="Widget.Material.Light.ActionButton"/>
+ <style name="Widget.DeviceDefault.Light.ActionButton.Overflow" parent="Widget.Material.Light.ActionButton.Overflow"/>
+ <style name="Widget.DeviceDefault.Light.ActionMode" parent="Widget.Material.Light.ActionMode"/>
+ <style name="Widget.DeviceDefault.Light.ActionButton.CloseMode" parent="Widget.Material.Light.ActionButton.CloseMode"/>
+ <style name="Widget.DeviceDefault.Light.ActionBar" parent="Widget.Material.Light.ActionBar"/>
+ <style name="Widget.DeviceDefault.Light.ActionBar.TabView" parent="Widget.Material.Light.ActionBar.TabView"/>
+ <style name="Widget.DeviceDefault.Light.ActionBar.TabText" parent="Widget.Material.Light.ActionBar.TabText"/>
+ <style name="Widget.DeviceDefault.Light.ActionBar.TabBar" parent="Widget.Material.Light.ActionBar.TabBar"/>
+ <style name="Widget.DeviceDefault.Light.ActionBar.Solid" parent="Widget.Material.Light.ActionBar.Solid"/>
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
<style name="Widget.DeviceDefault.Light.ActionBar.Solid.Inverse" parent="Widget.Holo.Light.ActionBar.Solid.Inverse"/>
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
@@ -185,98 +185,99 @@
<style name="Widget.DeviceDefault.Light.ActionBar.TabText.Inverse" parent="Widget.Holo.Light.ActionBar.TabText.Inverse"/>
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
<style name="Widget.DeviceDefault.Light.ActionMode.Inverse" parent="Widget.Holo.Light.ActionMode.Inverse"/>
- <style name="Widget.DeviceDefault.Light.AbsListView" parent="Widget.Quantum.Light.AbsListView"/>
- <style name="Widget.DeviceDefault.Light.Spinner.DropDown.ActionBar" parent="Widget.Quantum.Light.Spinner.DropDown.ActionBar"/>
- <style name="Widget.DeviceDefault.Light.PopupWindow.ActionMode" parent="Widget.Quantum.Light.PopupWindow.ActionMode"/>
- <style name="Widget.DeviceDefault.Light.Button.Borderless" parent="Widget.Quantum.Light.Button.Borderless"/>
- <style name="Widget.DeviceDefault.Light.DatePicker" parent="Widget.Quantum.Light.DatePicker"/>
- <style name="Widget.DeviceDefault.Light.ExpandableListView.White" parent="Widget.Quantum.Light.ExpandableListView.White"/>
- <style name="Widget.DeviceDefault.Light.Gallery" parent="Widget.Quantum.Light.Gallery"/>
- <style name="Widget.DeviceDefault.Light.GestureOverlayView" parent="Widget.Quantum.Light.GestureOverlayView"/>
- <style name="Widget.DeviceDefault.Light.ImageWell" parent="Widget.Quantum.Light.ImageWell"/>
- <style name="Widget.DeviceDefault.Light.ListView.White" parent="Widget.Quantum.Light.ListView.White"/>
- <style name="Widget.DeviceDefault.Light.NumberPicker" parent="Widget.Quantum.Light.NumberPicker"/>
- <style name="Widget.DeviceDefault.Light.Spinner.DropDown" parent="Widget.Quantum.Light.Spinner.DropDown"/>
- <style name="Widget.DeviceDefault.Light.TextView.ListSeparator" parent="Widget.Quantum.Light.TextView.ListSeparator"/>
- <style name="Widget.DeviceDefault.Light.TimePicker" parent="Widget.Quantum.Light.TimePicker"/>
- <style name="Widget.DeviceDefault.Light.TextSuggestionsPopupWindow" parent="Widget.Quantum.Light.TextSuggestionsPopupWindow"/>
+ <style name="Widget.DeviceDefault.Light.AbsListView" parent="Widget.Material.Light.AbsListView"/>
+ <style name="Widget.DeviceDefault.Light.Spinner.DropDown.ActionBar" parent="Widget.Material.Light.Spinner.DropDown.ActionBar"/>
+ <style name="Widget.DeviceDefault.Light.PopupWindow.ActionMode" parent="Widget.Material.Light.PopupWindow.ActionMode"/>
+ <style name="Widget.DeviceDefault.Light.Button.Borderless" parent="Widget.Material.Light.Button.Borderless"/>
+ <style name="Widget.DeviceDefault.Light.DatePicker" parent="Widget.Material.Light.DatePicker"/>
+ <style name="Widget.DeviceDefault.Light.ExpandableListView.White" parent="Widget.Material.Light.ExpandableListView.White"/>
+ <style name="Widget.DeviceDefault.Light.Gallery" parent="Widget.Material.Light.Gallery"/>
+ <style name="Widget.DeviceDefault.Light.GestureOverlayView" parent="Widget.Material.Light.GestureOverlayView"/>
+ <style name="Widget.DeviceDefault.Light.ImageWell" parent="Widget.Material.Light.ImageWell"/>
+ <style name="Widget.DeviceDefault.Light.ListView.White" parent="Widget.Material.Light.ListView.White"/>
+ <style name="Widget.DeviceDefault.Light.NumberPicker" parent="Widget.Material.Light.NumberPicker"/>
+ <style name="Widget.DeviceDefault.Light.Spinner.DropDown" parent="Widget.Material.Light.Spinner.DropDown"/>
+ <style name="Widget.DeviceDefault.Light.TextView.ListSeparator" parent="Widget.Material.Light.TextView.ListSeparator"/>
+ <style name="Widget.DeviceDefault.Light.TimePicker" parent="Widget.Material.Light.TimePicker"/>
+ <style name="Widget.DeviceDefault.Light.TextSuggestionsPopupWindow" parent="Widget.Material.Light.TextSuggestionsPopupWindow"/>
<!-- Text Appearance Styles -->
- <style name="TextAppearance.DeviceDefault" parent="TextAppearance.Quantum"/>
- <style name="TextAppearance.DeviceDefault.Inverse" parent="TextAppearance.Quantum.Inverse"/>
- <style name="TextAppearance.DeviceDefault.Large" parent="TextAppearance.Quantum.Large"/>
- <style name="TextAppearance.DeviceDefault.Large.Inverse" parent="TextAppearance.Quantum.Large.Inverse"/>
- <style name="TextAppearance.DeviceDefault.Medium" parent="TextAppearance.Quantum.Medium"/>
- <style name="TextAppearance.DeviceDefault.Medium.Inverse" parent="TextAppearance.Quantum.Medium.Inverse"/>
- <style name="TextAppearance.DeviceDefault.Small" parent="TextAppearance.Quantum.Small"/>
- <style name="TextAppearance.DeviceDefault.Small.Inverse" parent="TextAppearance.Quantum.Small.Inverse"/>
- <style name="TextAppearance.DeviceDefault.SearchResult.Title" parent="TextAppearance.Quantum.SearchResult.Title"/>
- <style name="TextAppearance.DeviceDefault.SearchResult.Subtitle" parent="TextAppearance.Quantum.SearchResult.Subtitle"/>
- <style name="TextAppearance.DeviceDefault.TimePicker.TimeLabel" parent="TextAppearance.Quantum.TimePicker.TimeLabel"/>
- <style name="TextAppearance.DeviceDefault.TimePicker.AmPmLabel" parent="TextAppearance.Quantum.TimePicker.AmPmLabel"/>
- <style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Quantum.Widget"/>
- <style name="TextAppearance.DeviceDefault.Widget.Button" parent="TextAppearance.Quantum.Widget.Button"/>
- <style name="TextAppearance.DeviceDefault.Widget.IconMenu.Item" parent="TextAppearance.Quantum.Widget.IconMenu.Item"/>
- <style name="TextAppearance.DeviceDefault.Widget.TabWidget" parent="TextAppearance.Quantum.Widget.TabWidget"/>
- <style name="TextAppearance.DeviceDefault.Widget.TextView" parent="TextAppearance.Quantum.Widget.TextView"/>
- <style name="TextAppearance.DeviceDefault.Widget.TextView.PopupMenu" parent="TextAppearance.Quantum.Widget.TextView.PopupMenu"/>
- <style name="TextAppearance.DeviceDefault.Widget.DropDownHint" parent="TextAppearance.Quantum.Widget.DropDownHint"/>
- <style name="TextAppearance.DeviceDefault.Widget.DropDownItem" parent="TextAppearance.Quantum.Widget.DropDownItem"/>
- <style name="TextAppearance.DeviceDefault.Widget.TextView.SpinnerItem" parent="TextAppearance.Quantum.Widget.TextView.SpinnerItem"/>
- <style name="TextAppearance.DeviceDefault.Widget.EditText" parent="TextAppearance.Quantum.Widget.EditText"/>
- <style name="TextAppearance.DeviceDefault.Widget.PopupMenu" parent="TextAppearance.Quantum.Widget.PopupMenu"/>
- <style name="TextAppearance.DeviceDefault.Widget.PopupMenu.Large" parent="TextAppearance.Quantum.Widget.PopupMenu.Large"/>
- <style name="TextAppearance.DeviceDefault.Widget.PopupMenu.Small" parent="TextAppearance.Quantum.Widget.PopupMenu.Small"/>
- <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Title" parent="TextAppearance.Quantum.Widget.ActionBar.Title"/>
- <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle" parent="TextAppearance.Quantum.Widget.ActionBar.Subtitle"/>
- <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Title" parent="TextAppearance.Quantum.Widget.ActionMode.Title"/>
- <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle" parent="TextAppearance.Quantum.Widget.ActionMode.Subtitle"/>
- <style name="TextAppearance.DeviceDefault.WindowTitle" parent="TextAppearance.Quantum.WindowTitle"/>
- <style name="TextAppearance.DeviceDefault.DialogWindowTitle" parent="TextAppearance.Quantum.DialogWindowTitle"/>
+ <style name="TextAppearance.DeviceDefault" parent="TextAppearance.Material"/>
+ <style name="TextAppearance.DeviceDefault.Inverse" parent="TextAppearance.Material.Inverse"/>
+ <style name="TextAppearance.DeviceDefault.Large" parent="TextAppearance.Material.Large"/>
+ <style name="TextAppearance.DeviceDefault.Large.Inverse" parent="TextAppearance.Material.Large.Inverse"/>
+ <style name="TextAppearance.DeviceDefault.Medium" parent="TextAppearance.Material.Medium"/>
+ <style name="TextAppearance.DeviceDefault.Medium.Inverse" parent="TextAppearance.Material.Medium.Inverse"/>
+ <style name="TextAppearance.DeviceDefault.Small" parent="TextAppearance.Material.Small"/>
+ <style name="TextAppearance.DeviceDefault.Small.Inverse" parent="TextAppearance.Material.Small.Inverse"/>
+ <style name="TextAppearance.DeviceDefault.SearchResult.Title" parent="TextAppearance.Material.SearchResult.Title"/>
+ <style name="TextAppearance.DeviceDefault.SearchResult.Subtitle" parent="TextAppearance.Material.SearchResult.Subtitle"/>
+ <style name="TextAppearance.DeviceDefault.TimePicker.TimeLabel" parent="TextAppearance.Material.TimePicker.TimeLabel"/>
+ <style name="TextAppearance.DeviceDefault.TimePicker.AmPmLabel" parent="TextAppearance.Material.TimePicker.AmPmLabel"/>
+ <style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Material.Widget"/>
+ <style name="TextAppearance.DeviceDefault.Widget.Button" parent="TextAppearance.Material.Widget.Button"/>
+ <style name="TextAppearance.DeviceDefault.Widget.IconMenu.Item" parent="TextAppearance.Material.Widget.IconMenu.Item"/>
+ <style name="TextAppearance.DeviceDefault.Widget.TabWidget" parent="TextAppearance.Material.Widget.TabWidget"/>
+ <style name="TextAppearance.DeviceDefault.Widget.TextView" parent="TextAppearance.Material.Widget.TextView"/>
+ <style name="TextAppearance.DeviceDefault.Widget.TextView.PopupMenu" parent="TextAppearance.Material.Widget.TextView.PopupMenu"/>
+ <style name="TextAppearance.DeviceDefault.Widget.DropDownHint" parent="TextAppearance.Material.Widget.DropDownHint"/>
+ <style name="TextAppearance.DeviceDefault.Widget.DropDownItem" parent="TextAppearance.Material.Widget.DropDownItem"/>
+ <style name="TextAppearance.DeviceDefault.Widget.TextView.SpinnerItem" parent="TextAppearance.Material.Widget.TextView.SpinnerItem"/>
+ <style name="TextAppearance.DeviceDefault.Widget.EditText" parent="TextAppearance.Material.Widget.EditText"/>
+ <style name="TextAppearance.DeviceDefault.Widget.PopupMenu" parent="TextAppearance.Material.Widget.PopupMenu"/>
+ <style name="TextAppearance.DeviceDefault.Widget.PopupMenu.Large" parent="TextAppearance.Material.Widget.PopupMenu.Large"/>
+ <style name="TextAppearance.DeviceDefault.Widget.PopupMenu.Small" parent="TextAppearance.Material.Widget.PopupMenu.Small"/>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Title" parent="TextAppearance.Material.Widget.ActionBar.Title"/>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle" parent="TextAppearance.Material.Widget.ActionBar.Subtitle"/>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Title" parent="TextAppearance.Material.Widget.ActionMode.Title"/>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle" parent="TextAppearance.Material.Widget.ActionMode.Subtitle"/>
+ <style name="TextAppearance.DeviceDefault.WindowTitle" parent="TextAppearance.Material.WindowTitle"/>
+ <style name="TextAppearance.DeviceDefault.DialogWindowTitle" parent="TextAppearance.Material.DialogWindowTitle"/>
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
- <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Title.Inverse" parent="TextAppearance.Quantum.Widget.ActionBar.Title.Inverse"/>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Title.Inverse" parent="TextAppearance.Material.Widget.ActionBar.Title.Inverse"/>
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
- <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle.Inverse" parent="TextAppearance.Quantum.Widget.ActionBar.Subtitle.Inverse"/>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle.Inverse" parent="TextAppearance.Material.Widget.ActionBar.Subtitle.Inverse"/>
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
- <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Title.Inverse" parent="TextAppearance.Quantum.Widget.ActionMode.Title.Inverse"/>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Title.Inverse" parent="TextAppearance.Material.Widget.ActionMode.Title.Inverse"/>
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
- <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.Quantum.Widget.ActionMode.Subtitle.Inverse"/>
- <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Menu" parent="TextAppearance.Quantum.Widget.ActionBar.Menu"/>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.Material.Widget.ActionMode.Subtitle.Inverse"/>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Menu" parent="TextAppearance.Material.Widget.ActionBar.Menu"/>
<!-- Preference Styles -->
- <style name="Preference.DeviceDefault" parent="Preference.Quantum"/>
- <style name="Preference.DeviceDefault.Category" parent="Preference.Quantum.Category"/>
- <style name="Preference.DeviceDefault.CheckBoxPreference" parent="Preference.Quantum.CheckBoxPreference"/>
- <style name="Preference.DeviceDefault.DialogPreference" parent="Preference.Quantum.DialogPreference"/>
- <style name="Preference.DeviceDefault.DialogPreference.EditTextPreference" parent="Preference.Quantum.DialogPreference.EditTextPreference"/>
- <style name="Preference.DeviceDefault.DialogPreference.YesNoPreference" parent="Preference.Quantum.DialogPreference.YesNoPreference"/>
- <style name="Preference.DeviceDefault.Information" parent="Preference.Quantum.Information"/>
- <style name="Preference.DeviceDefault.PreferenceScreen" parent="Preference.Quantum.PreferenceScreen"/>
- <style name="Preference.DeviceDefault.RingtonePreference" parent="Preference.Quantum.RingtonePreference"/>
- <style name="Preference.DeviceDefault.SwitchPreference" parent="Preference.Quantum.SwitchPreference"/>
+ <style name="Preference.DeviceDefault" parent="Preference.Material"/>
+ <style name="Preference.DeviceDefault.Category" parent="Preference.Material.Category"/>
+ <style name="Preference.DeviceDefault.CheckBoxPreference" parent="Preference.Material.CheckBoxPreference"/>
+ <style name="Preference.DeviceDefault.DialogPreference" parent="Preference.Material.DialogPreference"/>
+ <style name="Preference.DeviceDefault.DialogPreference.EditTextPreference" parent="Preference.Material.DialogPreference.EditTextPreference"/>
+ <style name="Preference.DeviceDefault.DialogPreference.YesNoPreference" parent="Preference.Material.DialogPreference.YesNoPreference"/>
+ <style name="Preference.DeviceDefault.Information" parent="Preference.Material.Information"/>
+ <style name="Preference.DeviceDefault.PreferenceScreen" parent="Preference.Material.PreferenceScreen"/>
+ <style name="Preference.DeviceDefault.RingtonePreference" parent="Preference.Material.RingtonePreference"/>
+ <style name="Preference.DeviceDefault.SwitchPreference" parent="Preference.Material.SwitchPreference"/>
+ <style name="Preference.DeviceDefault.SeekBarPreference" parent="Preference.Material.SeekBarPreference"/>
<!-- AlertDialog Styles -->
- <style name="AlertDialog.DeviceDefault" parent="AlertDialog.Quantum"/>
- <style name="AlertDialog.DeviceDefault.Light" parent="AlertDialog.Quantum.Light"/>
+ <style name="AlertDialog.DeviceDefault" parent="AlertDialog.Material"/>
+ <style name="AlertDialog.DeviceDefault.Light" parent="AlertDialog.Material.Light"/>
<!-- Animation Styles -->
- <style name="Animation.DeviceDefault.Activity" parent="Animation.Quantum.Activity"/>
- <style name="Animation.DeviceDefault.Dialog" parent="Animation.Quantum.Dialog"/>
+ <style name="Animation.DeviceDefault.Activity" parent="Animation.Material.Activity"/>
+ <style name="Animation.DeviceDefault.Dialog" parent="Animation.Material.Dialog"/>
<!-- DialogWindowTitle Styles -->
- <style name="DialogWindowTitle.DeviceDefault" parent="DialogWindowTitle.Quantum"/>
- <style name="DialogWindowTitle.DeviceDefault.Light" parent="DialogWindowTitle.Quantum.Light"/>
+ <style name="DialogWindowTitle.DeviceDefault" parent="DialogWindowTitle.Material"/>
+ <style name="DialogWindowTitle.DeviceDefault.Light" parent="DialogWindowTitle.Material.Light"/>
<!-- WindowTitle Styles -->
- <style name="WindowTitle.DeviceDefault" parent="WindowTitle.Quantum"/>
- <style name="WindowTitleBackground.DeviceDefault" parent="WindowTitleBackground.Quantum"/>
+ <style name="WindowTitle.DeviceDefault" parent="WindowTitle.Material"/>
+ <style name="WindowTitleBackground.DeviceDefault" parent="WindowTitleBackground.Material"/>
<!-- Other Styles -->
- <style name="DeviceDefault.ButtonBar" parent="Widget.Quantum.ButtonBar"/>
- <style name="DeviceDefault.ButtonBar.AlertDialog" parent="Widget.Quantum.ButtonBar.AlertDialog"/>
- <style name="DeviceDefault.SegmentedButton" parent="Widget.Quantum.SegmentedButton"/>
+ <style name="DeviceDefault.ButtonBar" parent="Widget.Material.ButtonBar"/>
+ <style name="DeviceDefault.ButtonBar.AlertDialog" parent="Widget.Material.ButtonBar.AlertDialog"/>
+ <style name="DeviceDefault.SegmentedButton" parent="Widget.Material.SegmentedButton"/>
- <style name="DeviceDefault.Light.ButtonBar" parent="Widget.Quantum.Light.ButtonBar"/>
- <style name="DeviceDefault.Light.ButtonBar.AlertDialog" parent="Widget.Quantum.Light.ButtonBar.AlertDialog"/>
- <style name="DeviceDefault.Light.SegmentedButton" parent="Widget.Quantum.Light.SegmentedButton"/>
+ <style name="DeviceDefault.Light.ButtonBar" parent="Widget.Material.Light.ButtonBar"/>
+ <style name="DeviceDefault.Light.ButtonBar.AlertDialog" parent="Widget.Material.Light.ButtonBar.AlertDialog"/>
+ <style name="DeviceDefault.Light.SegmentedButton" parent="Widget.Material.Light.SegmentedButton"/>
</resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
new file mode 100644
index 0000000..25307b9
--- /dev/null
+++ b/core/res/res/values/styles_material.xml
@@ -0,0 +1,1023 @@
+<?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.
+-->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+<resources>
+ <!-- Preference styles -->
+ <eat-comment/>
+
+ <style name="Preference.Material">
+ <item name="layout">@layout/preference_material</item>
+ </style>
+
+ <style name="PreferenceFragment.Material">
+ <item name="paddingStart">@dimen/preference_fragment_padding_side_material</item>
+ <item name="paddingEnd">@dimen/preference_fragment_padding_side_material</item>
+ </style>
+
+ <style name="Preference.Material.Information">
+ <item name="layout">@layout/preference_information_material</item>
+ <item name="enabled">false</item>
+ <item name="shouldDisableView">false</item>
+ </style>
+
+ <style name="Preference.Material.Category">
+ <item name="layout">@layout/preference_category_material</item>
+ <!-- The title should not dim if the category is disabled, instead only the preference children should dim. -->
+ <item name="shouldDisableView">false</item>
+ <item name="selectable">false</item>
+ </style>
+
+ <style name="Preference.Material.CheckBoxPreference">
+ <item name="widgetLayout">@layout/preference_widget_checkbox</item>
+ </style>
+
+ <style name="Preference.Material.SwitchPreference">
+ <item name="widgetLayout">@layout/preference_widget_switch</item>
+ <item name="switchTextOn">@string/capital_on</item>
+ <item name="switchTextOff">@string/capital_off</item>
+ </style>
+
+ <style name="Preference.Material.SeekBarPreference">
+ <item name="layout">@android:layout/preference_widget_seekbar_material</item>
+ </style>
+
+ <style name="Preference.Material.PreferenceScreen"/>
+
+ <style name="Preference.Material.DialogPreference">
+ <item name="positiveButtonText">@string/ok</item>
+ <item name="negativeButtonText">@string/cancel</item>
+ </style>
+
+ <style name="Preference.Material.DialogPreference.YesNoPreference">
+ <item name="positiveButtonText">@string/yes</item>
+ <item name="negativeButtonText">@string/no</item>
+ </style>
+
+ <style name="Preference.Material.DialogPreference.EditTextPreference">
+ <item name="dialogLayout">@layout/preference_dialog_edittext</item>
+ </style>
+
+ <style name="Preference.Material.RingtonePreference">
+ <item name="ringtoneType">ringtone</item>
+ <item name="showSilent">true</item>
+ <item name="showDefault">true</item>
+ </style>
+
+ <!-- No margins or background by default. Could be different for x-large screens -->
+ <style name="PreferencePanel.Material">
+ </style>
+
+ <!-- The attributes are overridden here because the x-large or large resources may have
+ changed the margins and background in the parent PreferencePanel style. -->
+ <style name="PreferencePanel.Material.Dialog">
+ <item name="layout_marginStart">0dip</item>
+ <item name="layout_marginEnd">0dip</item>
+ <item name="layout_marginTop">0dip</item>
+ <item name="layout_marginBottom">0dip</item>
+ <item name="background">@null</item>
+ </style>
+
+ <style name="PreferenceHeaderPanel.Material">
+ <item name="layout_marginStart">@dimen/preference_screen_side_margin</item>
+ <item name="layout_marginEnd">@dimen/preference_screen_side_margin_negative</item>
+ <item name="paddingTop">@dimen/preference_screen_header_vertical_padding</item>
+ <item name="paddingBottom">@dimen/preference_screen_header_vertical_padding</item>
+ </style>
+
+ <style name="PreferenceHeaderList.Material">
+ <item name="paddingStart">@dimen/preference_screen_header_padding_side_material</item>
+ <item name="paddingEnd">@dimen/preference_screen_header_padding_side_material</item>
+ <item name="scrollbarStyle">@integer/preference_screen_header_scrollbarStyle</item>
+ </style>
+
+ <style name="PreferenceFragmentList.Material">
+ <item name="paddingStart">@dimen/preference_fragment_padding_side_material</item>
+ <item name="paddingEnd">@dimen/preference_fragment_padding_side_material</item>
+ </style>
+
+ <!-- Begin Material theme styles -->
+
+ <!-- Text styles -->
+
+ <style name="TextAppearance.Material">
+ <item name="textColor">?attr/textColorPrimary</item>
+ <item name="textColorHint">?attr/textColorHint</item>
+ <item name="textColorHighlight">?attr/textColorHighlight</item>
+ <item name="textColorLink">?attr/textColorLink</item>
+ <item name="textSize">@dimen/text_size_body_1_material</item>
+ <item name="fontFamily">@string/font_family_body_1_material</item>
+ </style>
+
+ <style name="TextAppearance.Material.Display4">
+ <item name="textSize">@dimen/text_size_display_4_material</item>
+ <item name="fontFamily">@string/font_family_display_4_material</item>
+ <item name="textColor">?attr/textColorSecondary</item>
+ </style>
+
+ <style name="TextAppearance.Material.Display3">
+ <item name="textSize">@dimen/text_size_display_3_material</item>
+ <item name="fontFamily">@string/font_family_display_3_material</item>
+ <item name="textColor">?attr/textColorSecondary</item>
+ </style>
+
+ <style name="TextAppearance.Material.Display2">
+ <item name="textSize">@dimen/text_size_display_2_material</item>
+ <item name="fontFamily">@string/font_family_display_2_material</item>
+ <item name="textColor">?attr/textColorSecondary</item>
+ </style>
+
+ <style name="TextAppearance.Material.Display1">
+ <item name="textSize">@dimen/text_size_display_1_material</item>
+ <item name="fontFamily">@string/font_family_display_1_material</item>
+ <item name="textColor">?attr/textColorSecondary</item>
+ </style>
+
+ <style name="TextAppearance.Material.Headline">
+ <item name="textSize">@dimen/text_size_headline_material</item>
+ <item name="fontFamily">@string/font_family_headline_material</item>
+ <item name="textColor">?attr/textColorPrimary</item>
+ </style>
+
+ <style name="TextAppearance.Material.Title">
+ <item name="textSize">@dimen/text_size_title_material</item>
+ <item name="fontFamily">@string/font_family_title_material</item>
+ <item name="textColor">?attr/textColorPrimary</item>
+ </style>
+
+ <style name="TextAppearance.Material.Title.Inverse">
+ <item name="textColor">?attr/textColorPrimaryInverse</item>
+ <item name="textColorHint">?attr/textColorHintInverse</item>
+ <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
+ <item name="textColorLink">?attr/textColorLinkInverse</item>
+ </style>
+
+ <style name="TextAppearance.Material.Subhead">
+ <item name="textSize">@dimen/text_size_subhead_material</item>
+ <item name="fontFamily">@string/font_family_subhead_material</item>
+ <item name="textColor">?attr/textColorPrimary</item>
+ </style>
+
+ <style name="TextAppearance.Material.Subhead.Inverse">
+ <item name="textColor">?attr/textColorSecondaryInverse</item>
+ <item name="textColorHint">?attr/textColorHintInverse</item>
+ <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
+ <item name="textColorLink">?attr/textColorLinkInverse</item>
+ </style>
+
+ <style name="TextAppearance.Material.Body2">
+ <item name="textSize">@dimen/text_size_body_2_material</item>
+ <item name="fontFamily">@string/font_family_body_2_material</item>
+ <item name="textColor">?attr/textColorPrimary</item>
+ </style>
+
+ <style name="TextAppearance.Material.Body1">
+ <item name="textSize">@dimen/text_size_body_1_material</item>
+ <item name="fontFamily">@string/font_family_body_1_material</item>
+ <item name="textColor">?attr/textColorPrimary</item>
+ </style>
+
+ <style name="TextAppearance.Material.Caption">
+ <item name="textSize">@dimen/text_size_caption_material</item>
+ <item name="fontFamily">@string/font_family_caption_material</item>
+ <item name="textColor">?attr/textColorSecondary</item>
+ </style>
+
+ <style name="TextAppearance.Material.Menu">
+ <item name="textSize">@dimen/text_size_menu_material</item>
+ <item name="fontFamily">@string/font_family_menu_material</item>
+ </style>
+
+ <style name="TextAppearance.Material.Menu.Inverse">
+ <item name="textColor">?attr/textColorSecondaryInverse</item>
+ <item name="textColorHint">?attr/textColorHintInverse</item>
+ <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
+ <item name="textColorLink">?attr/textColorLinkInverse</item>
+ </style>
+
+ <style name="TextAppearance.Material.Button">
+ <item name="textSize">@dimen/text_size_button_material</item>
+ <item name="fontFamily">@string/font_family_button_material</item>
+ <item name="textAllCaps">true</item>
+ <item name="textColor">?attr/textColorPrimary</item>
+ </style>
+
+ <!-- Deprecated text styles -->
+
+ <style name="TextAppearance.Material.Inverse">
+ <item name="textColor">?attr/textColorPrimaryInverse</item>
+ <item name="textColorHint">?attr/textColorHintInverse</item>
+ <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
+ <item name="textColorLink">?attr/textColorLinkInverse</item>
+ </style>
+
+ <style name="TextAppearance.Material.Large">
+ <item name="textSize">@dimen/text_size_large_material</item>
+ <item name="textColor">?attr/textColorPrimary</item>
+ </style>
+
+ <style name="TextAppearance.Material.Large.Inverse">
+ <item name="textColor">?attr/textColorPrimaryInverse</item>
+ <item name="textColorHint">?attr/textColorHintInverse</item>
+ <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
+ <item name="textColorLink">?attr/textColorLinkInverse</item>
+ </style>
+
+ <style name="TextAppearance.Material.Medium">
+ <item name="textSize">@dimen/text_size_medium_material</item>
+ <item name="textColor">?attr/textColorSecondary</item>
+ </style>
+
+ <style name="TextAppearance.Material.Medium.Inverse">
+ <item name="textColor">?attr/textColorSecondaryInverse</item>
+ <item name="textColorHint">?attr/textColorHintInverse</item>
+ <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
+ <item name="textColorLink">?attr/textColorLinkInverse</item>
+ </style>
+
+ <style name="TextAppearance.Material.Small">
+ <item name="textSize">@dimen/text_size_small_material</item>
+ <item name="textColor">?attr/textColorTertiary</item>
+ </style>
+
+ <style name="TextAppearance.Material.Small.Inverse">
+ <item name="textColor">?attr/textColorTertiaryInverse</item>
+ <item name="textColorHint">?attr/textColorHintInverse</item>
+ <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
+ <item name="textColorLink">?attr/textColorLinkInverse</item>
+ </style>
+
+ <style name="TextAppearance.Material.SearchResult" />
+ <style name="TextAppearance.Material.SearchResult.Title" parent="TextAppearance.Material.Title" />
+ <style name="TextAppearance.Material.SearchResult.Subtitle" parent="TextAppearance.Material.Subhead" />
+
+ <style name="TextAppearance.Material.Widget"/>
+ <style name="TextAppearance.Material.Widget.Button" parent="TextAppearance.Material.Button" />
+
+ <style name="TextAppearance.Material.Widget.EditText">
+ <item name="textColor">?attr/textColorPrimaryInverse</item>
+ <item name="textColorHint">?attr/textColorHintInverse</item>
+ </style>
+
+ <style name="TextAppearance.Material.Widget.Switch" parent="TextAppearance.Material.Button" />
+
+ <style name="TextAppearance.Material.Widget.PopupMenu"/>
+ <style name="TextAppearance.Material.Widget.PopupMenu.Large" parent="TextAppearance.Material.Menu" />
+ <style name="TextAppearance.Material.Widget.PopupMenu.Small" parent="TextAppearance.Material.Menu" />
+
+ <style name="TextAppearance.Material.Widget.DropDownHint" parent="TextAppearance.Material.Menu" />
+
+ <style name="TextAppearance.Material.Widget.IconMenu.Item" parent="TextAppearance.Material.Small">
+ <item name="textColor">?attr/textColorPrimary</item>
+ </style>
+
+ <style name="TextAppearance.Material.Widget.TabWidget" parent="TextAppearance.Material.Button" />
+
+ <style name="TextAppearance.Material.Widget.TextView">
+ <item name="textColor">?attr/textColorPrimaryDisableOnly</item>
+ <item name="textColorHint">?attr/textColorHint</item>
+ </style>
+
+ <style name="TextAppearance.Material.Widget.TextView.PopupMenu" parent="TextAppearance.Material.Menu" />
+ <style name="TextAppearance.Material.Widget.TextView.SpinnerItem" />
+
+ <style name="TextAppearance.Material.Widget.DropDownItem">
+ <item name="textColor">?attr/textColorPrimaryDisableOnly</item>
+ </style>
+
+ <style name="TextAppearance.Material.Widget.ActionMode"/>
+ <style name="TextAppearance.Material.Widget.ActionMode.Title" parent="TextAppearance.Material.Title" />
+ <style name="TextAppearance.Material.Widget.ActionMode.Title.Inverse" parent="TextAppearance.Material.Title.Inverse" />
+ <style name="TextAppearance.Material.Widget.ActionMode.Subtitle" parent="TextAppearance.Material.Subhead" />
+ <style name="TextAppearance.Material.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.Material.Subhead.Inverse" />
+
+ <style name="TextAppearance.Material.Widget.ActionBar.Title" parent="TextAppearance.Material.Title" />
+ <style name="TextAppearance.Material.Widget.ActionBar.Title.Inverse" parent="TextAppearance.Material.Title.Inverse" />
+ <style name="TextAppearance.Material.Widget.ActionBar.Subtitle" parent="TextAppearance.Material.Subhead" />
+ <style name="TextAppearance.Material.Widget.ActionBar.Subtitle.Inverse" parent="TextAppearance.Material.Subhead.Inverse" />
+
+ <style name="TextAppearance.Material.Widget.ActionBar.Menu" parent="TextAppearance.Material.Menu">
+ <item name="textColor">?attr/actionMenuTextColor</item>
+ <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item>
+ </style>
+
+ <style name="TextAppearance.Material.Widget.ActionBar.Menu.Inverse" parent="TextAppearance.Material.Menu.Inverse">
+ <item name="textColor">?attr/actionMenuTextColor</item>
+ <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item>
+ </style>
+
+ <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>
+
+ <style name="TextAppearance.Material.TimePicker.TimeLabel" parent="TextAppearance.Material">
+ <item name="textSize">@dimen/timepicker_time_label_size</item>
+ <item name="textColor">?attr/textColorSecondary</item>
+ </style>
+
+ <style name="TextAppearance.Material.TimePicker.AmPmLabel" parent="TextAppearance.Material">
+ <item name="textSize">@dimen/timepicker_ampm_label_size</item>
+ <item name="textAllCaps">true</item>
+ <item name="textColor">?attr/textColorSecondary</item>
+ <item name="textStyle">bold</item>
+ </style>
+
+ <style name="TextAppearance.StatusBar.Material" />
+
+ <style name="TextAppearance.StatusBar.Material.EventContent">
+ <item name="android:textColor">#90000000</item>
+ <item name="android:textSize">@dimen/notification_text_size</item>
+ </style>
+
+ <style name="TextAppearance.StatusBar.Material.EventContent.Title">
+ <item name="android:textColor">#DD000000</item>
+ <item name="android:textSize">@dimen/notification_title_text_size</item>
+ </style>
+
+ <style name="TextAppearance.StatusBar.Material.EventContent.Line2">
+ <item name="android:textSize">@dimen/notification_subtext_size</item>
+ </style>
+
+ <style name="TextAppearance.StatusBar.Material.EventContent.Info">
+ <item name="android:textSize">@dimen/notification_subtext_size</item>
+ </style>
+
+ <style name="TextAppearance.StatusBar.Material.EventContent.Time">
+ <item name="android:textSize">@dimen/notification_subtext_size</item>
+ </style>
+
+ <style name="TextAppearance.StatusBar.Material.EventContent.Emphasis">
+ <item name="android:textColor">#66000000</item>
+ </style>
+
+ <style name="Widget.StatusBar.Material.ProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal" />
+
+ <style name="Widget.StatusBar.Material.ProgressBar.Media">
+ <item name="android:progressDrawable">@drawable/notification_material_media_progress</item>
+ </style>
+
+ <!-- Widget Styles -->
+
+ <style name="Material"/>
+ <style name="Material.Light"/>
+ <style name="Widget.Material" parent="Widget" />
+
+ <!-- Bordered ink button -->
+ <style name="Widget.Material.Button" parent="Widget.Button">
+ <item name="background">@drawable/btn_default_material</item>
+ <item name="textAppearance">?attr/textAppearanceButton</item>
+ <item name="textColor">?attr/textColorPrimary</item>
+ <item name="minHeight">48dip</item>
+ <item name="minWidth">88dip</item>
+
+ <!-- TODO: Turn this back on when we support inset drawable outlines. -->
+ <!-- <item name="stateListAnimator">@anim/button_state_list_anim_material</item> -->
+ </style>
+
+ <!-- Small bordered ink button -->
+ <style name="Widget.Material.Button.Small">
+ <item name="minHeight">48dip</item>
+ <item name="minWidth">48dip</item>
+ </style>
+
+ <!-- Borderless ink button -->
+ <style name="Widget.Material.Button.Borderless">
+ <item name="background">@drawable/btn_borderless_material</item>
+ <item name="stateListAnimator">@null</item>
+ </style>
+
+ <!-- Small borderless ink button -->
+ <style name="Widget.Material.Button.Borderless.Small">
+ <item name="minHeight">48dip</item>
+ <item name="minWidth">48dip</item>
+ </style>
+
+ <style name="Widget.Material.Button.Inset">
+ <item name="background">@drawable/button_inset</item>
+ </style>
+
+ <style name="Widget.Material.Button.Toggle">
+ <item name="background">@drawable/btn_toggle_material</item>
+ <item name="textOn">@string/capital_on</item>
+ <item name="textOff">@string/capital_off</item>
+ <item name="minHeight">48dip</item>
+ </style>
+
+ <style name="Widget.Material.ButtonBar">
+ <item name="background">@null</item>
+ </style>
+
+ <style name="Widget.Material.ButtonBar.AlertDialog">
+ <item name="background">@null</item>
+ </style>
+
+ <style name="Widget.Material.SegmentedButton" parent="SegmentedButton">
+ <item name="background">@drawable/btn_group_holo_dark</item>
+ </style>
+
+ <style name="Widget.Material.StackView">
+ <item name="resOutColor">@color/holo_blue_light</item>
+ <item name="clickColor">@color/holo_blue_light</item>
+ </style>
+
+ <style name="Widget.Material.TextView" parent="Widget.TextView"/>
+
+ <style name="Widget.Material.TextView.ListSeparator" parent="Widget.TextView.ListSeparator">
+ <item name="background">@drawable/list_section_divider_material</item>
+ <item name="textAllCaps">true</item>
+ </style>
+
+ <style name="Widget.Material.TextView.SpinnerItem" parent="Widget.TextView.SpinnerItem">
+ <item name="textAppearance">@style/TextAppearance.Material.Widget.TextView.SpinnerItem</item>
+ <item name="paddingStart">8dp</item>
+ <item name="paddingEnd">8dp</item>
+ </style>
+
+ <style name="Widget.Material.CheckedTextView" parent="Widget.CheckedTextView" />
+ <style name="Widget.Material.TextSelectHandle" parent="Widget.TextSelectHandle"/>
+ <style name="Widget.Material.TextSuggestionsPopupWindow" parent="Widget.TextSuggestionsPopupWindow"/>
+ <style name="Widget.Material.AbsListView" parent="Widget.AbsListView"/>
+
+ <style name="Widget.Material.AutoCompleteTextView" parent="Widget.AutoCompleteTextView">
+ <item name="dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
+ <item name="popupBackground">@drawable/popup_background_material</item>
+ </style>
+
+ <style name="Widget.Material.CompoundButton" parent="Widget.CompoundButton"/>
+
+ <style name="Widget.Material.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox">
+ <item name="background">?attr/selectableItemBackgroundBorderless</item>
+ </style>
+
+ <style name="Widget.Material.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton">
+ <item name="background">?attr/selectableItemBackgroundBorderless</item>
+ </style>
+
+ <style name="Widget.Material.CompoundButton.Star" parent="Widget.CompoundButton.Star">
+ <item name="button">@drawable/btn_star_material</item>
+ <item name="background">?attr/selectableItemBackgroundBorderless</item>
+ </style>
+
+ <style name="Widget.Material.CompoundButton.Switch">
+ <item name="track">@drawable/switch_track_material</item>
+ <item name="thumb">@drawable/switch_thumb_material_anim</item>
+ <item name="splitTrack">true</item>
+ <item name="switchTextAppearance">@style/TextAppearance.Material.Widget.Switch</item>
+ <item name="textOn"></item>
+ <item name="textOff"></item>
+ <item name="switchMinWidth">4dip</item>
+ <item name="switchPadding">4dip</item>
+ <item name="background">?attr/selectableItemBackgroundBorderless</item>
+ </style>
+
+ <style name="Widget.Material.EditText" parent="Widget.EditText"/>
+
+ <style name="Widget.Material.ExpandableListView" parent="Widget.Material.ListView">
+ <item name="groupIndicator">@drawable/expander_group_material</item>
+ <item name="indicatorLeft">?attr/expandableListPreferredItemIndicatorLeft</item>
+ <item name="indicatorRight">?attr/expandableListPreferredItemIndicatorRight</item>
+ <item name="childDivider">?attr/listDivider</item>
+ </style>
+
+ <style name="Widget.Material.ExpandableListView.White"/>
+ <style name="Widget.Material.Gallery" parent="Widget.Gallery"/>
+ <style name="Widget.Material.GestureOverlayView" parent="Widget.GestureOverlayView"/>
+
+ <style name="Widget.Material.GridView" parent="Widget.GridView">
+ <item name="android:listSelector">?attr/selectableItemBackground</item>
+ </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>
+ </style>
+
+ <style name="Widget.Material.ImageButton" parent="Widget.ImageButton">
+ <item name="background">@drawable/btn_default_material</item>
+ </style>
+
+ <style name="Widget.Material.NumberPicker" parent="Widget.NumberPicker">
+ <item name="internalLayout">@layout/number_picker_with_selector_wheel</item>
+ <item name="solidColor">@color/transparent</item>
+ <item name="selectionDivider">@drawable/numberpicker_selection_divider</item>
+ <item name="selectionDividerHeight">2dip</item>
+ <item name="selectionDividersDistance">48dip</item>
+ <item name="internalMinWidth">64dip</item>
+ <item name="internalMaxHeight">180dip</item>
+ <item name="virtualButtonPressedDrawable">?attr/selectableItemBackground</item>
+ </style>
+
+ <style name="Widget.Material.TimePicker" parent="Widget.TimePicker">
+ <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
+ <item name="internalLayout">@layout/time_picker_holo</item>
+ <item name="disabledColor">@color/bright_foreground_disabled_material_dark</item>
+ <item name="headerSelectedTextColor">?attr/colorControlActivated</item>
+ <item name="headerUnselectedTextColor">?attr/textColorPrimary</item>
+ <item name="headerBackgroundColor">@color/transparent</item>
+ <item name="numbersTextColor">?attr/textColorSecondary</item>
+ <item name="numbersBackgroundColor">@color/transparent</item>
+ <item name="amPmTextColor">?attr/textColorSecondary</item>
+ <item name="amPmUnselectedBackgroundColor">@color/transparent</item>
+ <item name="amPmSelectedBackgroundColor">?attr/colorControlActivated</item>
+ <item name="numbersSelectorColor">?attr/colorControlActivated</item>
+ </style>
+
+ <style name="Widget.Material.DatePicker" parent="Widget.DatePicker">
+ <item name="internalLayout">@layout/date_picker_holo</item>
+ <item name="calendarViewShown">true</item>
+ </style>
+
+ <style name="Widget.Material.ActivityChooserView" parent="Widget.ActivityChooserView">
+ <item name="background">@drawable/ab_share_pack_material</item>
+ </style>
+
+ <style name="Widget.Material.ImageWell" parent="Widget.ImageWell"/>
+
+ <style name="Widget.Material.ListView" parent="Widget.ListView">
+ <item name="divider">?attr/listDivider</item>
+ <item name="listSelector">?attr/listChoiceBackgroundIndicator</item>
+ </style>
+
+ <style name="Widget.Material.ListView.DropDown"/>
+ <style name="Widget.Material.ListView.White"/>
+
+ <style name="Widget.Material.PopupWindow" parent="Widget.PopupWindow"/>
+
+ <style name="Widget.Material.PopupWindow.ActionMode">
+ <item name="popupBackground">@drawable/popup_background_material</item>
+ <item name="popupAnimationStyle">@style/Animation.PopupWindow.ActionMode</item>
+ </style>
+
+ <style name="Widget.Material.ProgressBar" parent="Widget.ProgressBar">
+ <item name="indeterminateDrawable">@drawable/progress_medium_material</item>
+ </style>
+
+ <style name="Widget.Material.ProgressBar.Inverse"/>
+
+ <style name="Widget.Material.ProgressBar.Horizontal" parent="Widget.ProgressBar.Horizontal">
+ <item name="progressDrawable">@drawable/progress_horizontal_material</item>
+ <item name="indeterminateDrawable">@drawable/progress_indeterminate_horizontal_holo</item>
+ <item name="minHeight">16dip</item>
+ <item name="maxHeight">16dip</item>
+ </style>
+
+ <style name="Widget.Material.ProgressBar.Small" parent="Widget.ProgressBar.Small">
+ <item name="indeterminateDrawable">@drawable/progress_small_material</item>
+ </style>
+
+ <style name="Widget.Material.ProgressBar.Small.Inverse"/>
+ <style name="Widget.Material.ProgressBar.Small.Title"/>
+
+ <style name="Widget.Material.ProgressBar.Large" parent="Widget.ProgressBar.Large">
+ <item name="indeterminateDrawable">@drawable/progress_large_material</item>
+ </style>
+
+ <style name="Widget.Material.ProgressBar.Large.Inverse"/>
+
+ <style name="Widget.Material.SeekBar">
+ <item name="indeterminateOnly">false</item>
+ <item name="progressDrawable">@drawable/scrubber_progress_horizontal_material</item>
+ <item name="indeterminateDrawable">@drawable/scrubber_progress_horizontal_material</item>
+ <item name="thumb">@drawable/scrubber_control_material_anim</item>
+ <item name="splitTrack">true</item>
+ <item name="focusable">true</item>
+ <item name="paddingStart">16dip</item>
+ <item name="paddingEnd">16dip</item>
+ <item name="mirrorForRtl">true</item>
+ <item name="background">?attr/selectableItemBackgroundBorderless</item>
+ </style>
+
+ <style name="Widget.Material.RatingBar" parent="Widget.RatingBar">
+ <item name="progressDrawable">@drawable/ratingbar_full_material</item>
+ <item name="indeterminateDrawable">@drawable/ratingbar_full_material</item>
+ </style>
+
+ <style name="Widget.Material.RatingBar.Indicator" parent="Widget.RatingBar.Indicator">
+ <item name="progressDrawable">@drawable/ratingbar_holo_dark</item>
+ <item name="indeterminateDrawable">@drawable/ratingbar_holo_dark</item>
+ <item name="minHeight">35dip</item>
+ <item name="maxHeight">35dip</item>
+ </style>
+
+ <style name="Widget.Material.RatingBar.Small" parent="Widget.RatingBar.Small">
+ <item name="progressDrawable">@drawable/ratingbar_small_holo_dark</item>
+ <item name="indeterminateDrawable">@drawable/ratingbar_small_holo_dark</item>
+ <item name="minHeight">16dip</item>
+ <item name="maxHeight">16dip</item>
+ </style>
+
+ <style name="Widget.Material.ScrollView" parent="Widget.ScrollView"/>
+ <style name="Widget.Material.HorizontalScrollView" parent="Widget.HorizontalScrollView"/>
+
+ <style name="Widget.Material.Spinner" parent="Widget.Spinner.DropDown">
+ <item name="background">@drawable/spinner_background_material</item>
+ <item name="dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
+ <item name="popupBackground">@drawable/popup_background_material</item>
+ <item name="dropDownVerticalOffset">0dip</item>
+ <item name="dropDownHorizontalOffset">0dip</item>
+ <item name="dropDownWidth">wrap_content</item>
+ <item name="popupPromptView">@layout/simple_dropdown_hint</item>
+ <item name="gravity">start|center_vertical</item>
+ <item name="disableChildrenWhenDisabled">true</item>
+ </style>
+
+ <style name="Widget.Material.Spinner.DropDown"/>
+
+ <style name="Widget.Material.Spinner.DropDown.ActionBar">
+ <item name="background">@drawable/spinner_background_material</item>
+ <item name="overlapAnchor">true</item>
+ </style>
+
+ <style name="Widget.Material.TabWidget" parent="Widget.TabWidget">
+ <item name="tabStripLeft">@null</item>
+ <item name="tabStripRight">@null</item>
+ <item name="tabStripEnabled">false</item>
+ <item name="divider">?attr/dividerVertical</item>
+ <item name="showDividers">middle</item>
+ <item name="dividerPadding">8dip</item>
+ <item name="measureWithLargestChild">true</item>
+ <item name="tabLayout">@layout/tab_indicator_material</item>
+ </style>
+
+ <style name="Widget.Material.Tab" parent="Widget.Material.ActionBar.TabView">
+ <item name="background">@drawable/tab_indicator_material</item>
+ <item name="layout_width">0dip</item>
+ <item name="layout_weight">1</item>
+ <item name="minWidth">80dip</item>
+ </style>
+
+ <style name="Widget.Material.TabText" parent="Widget.Material.ActionBar.TabText">
+ <item name="maxWidth">180dip</item>
+ </style>
+
+ <style name="Widget.Material.Toolbar" parent="Widget.Toolbar">
+ <item name="android:navigationButtonStyle">@android:style/Widget.Material.Toolbar.Button.Navigation</item>
+ </style>
+
+ <style name="Widget.Material.Toolbar.Button.Navigation" parent="Widget.Toolbar.Button.Navigation">
+ <item name="android:background">?attr/selectableItemBackgroundBorderless</item>
+ </style>
+
+ <style name="Widget.Material.WebTextView" parent="Widget.WebTextView"/>
+
+ <style name="Widget.Material.WebView" parent="Widget.WebView"/>
+
+ <style name="Widget.Material.DropDownItem" parent="Widget.DropDownItem">
+ <item name="textAppearance">@style/TextAppearance.Material.Widget.DropDownItem</item>
+ <item name="paddingStart">8dp</item>
+ <item name="paddingEnd">8dp</item>
+ </style>
+
+ <style name="Widget.Material.DropDownItem.Spinner"/>
+
+ <style name="Widget.Material.KeyboardView" parent="Widget.KeyboardView"/>
+ <style name="Widget.Material.QuickContactBadge.WindowSmall" parent="Widget.QuickContactBadge.WindowSmall"/>
+ <style name="Widget.Material.QuickContactBadge.WindowMedium" parent="Widget.QuickContactBadge.WindowMedium"/>
+ <style name="Widget.Material.QuickContactBadge.WindowLarge" parent="Widget.QuickContactBadge.WindowLarge"/>
+ <style name="Widget.Material.QuickContactBadgeSmall.WindowSmall" parent="Widget.QuickContactBadgeSmall.WindowSmall"/>
+ <style name="Widget.Material.QuickContactBadgeSmall.WindowMedium" parent="Widget.QuickContactBadgeSmall.WindowMedium"/>
+ <style name="Widget.Material.QuickContactBadgeSmall.WindowLarge" parent="Widget.QuickContactBadgeSmall.WindowLarge"/>
+
+ <style name="Widget.Material.ListPopupWindow" parent="Widget.ListPopupWindow">
+ <item name="dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
+ <item name="popupBackground">@drawable/popup_background_material</item>
+ <item name="popupAnimationStyle">@style/Animation.Material.Popup</item>
+ <item name="dropDownVerticalOffset">0dip</item>
+ <item name="dropDownHorizontalOffset">0dip</item>
+ <item name="dropDownWidth">wrap_content</item>
+ </style>
+
+ <style name="Widget.Material.PopupMenu" parent="Widget.Material.ListPopupWindow"/>
+
+ <style name="Widget.Material.PopupMenu.Overflow">
+ <item name="overlapAnchor">true</item>
+ </style>
+
+ <style name="Widget.Material.ActionButton" parent="Widget.ActionButton">
+ <item name="minWidth">@dimen/action_button_min_width_material</item>
+ <item name="minHeight">@dimen/action_button_min_height_material</item>
+ <item name="gravity">center</item>
+ <item name="scaleType">center</item>
+ <item name="maxLines">2</item>
+ </style>
+
+ <style name="Widget.Material.ActionButton.CloseMode">
+ <item name="background">@drawable/btn_cab_done_material</item>
+ </style>
+
+ <style name="Widget.Material.ActionButton.Overflow">
+ <item name="src">@drawable/ic_menu_moreoverflow_material</item>
+ <item name="background">?attr/actionBarItemBackground</item>
+ <item name="contentDescription">@string/action_menu_overflow_description</item>
+ <item name="minWidth">@dimen/action_overflow_min_width_material</item>
+ <item name="minHeight">@dimen/action_button_min_height_material</item>
+ <item name="scaleType">center</item>
+ </style>
+
+ <style name="Widget.Material.ActionBar.TabView" parent="Widget.ActionBar.TabView">
+ <item name="background">@drawable/tab_indicator_material</item>
+ <item name="paddingStart">16dip</item>
+ <item name="paddingEnd">16dip</item>
+ </style>
+
+ <style name="Widget.Material.ActionBar.TabBar" parent="Widget.ActionBar.TabBar">
+ <item name="divider">?attr/actionBarDivider</item>
+ <item name="showDividers">middle</item>
+ <item name="dividerPadding">12dip</item>
+ </style>
+
+ <style name="Widget.Material.ActionBar.TabText" parent="Widget.ActionBar.TabText">
+ <item name="textAppearance">@style/TextAppearance.Material.Medium</item>
+ <item name="textColor">?attr/textColorPrimary</item>
+ <item name="textSize">12sp</item>
+ <item name="textStyle">bold</item>
+ <item name="textAllCaps">true</item>
+ <item name="ellipsize">marquee</item>
+ <item name="maxLines">2</item>
+ </style>
+
+ <style name="Widget.Material.ActionBar" parent="Widget.ActionBar">
+ <item name="background">@null</item>
+ <item name="backgroundStacked">@null</item>
+ <item name="backgroundSplit">@null</item>
+ <item name="displayOptions">showTitle</item>
+ <item name="divider">?attr/dividerVertical</item>
+ <item name="titleTextStyle">@style/TextAppearance.Material.Widget.ActionBar.Title</item>
+ <item name="subtitleTextStyle">@style/TextAppearance.Material.Widget.ActionBar.Subtitle</item>
+ <item name="progressBarStyle">@style/Widget.Material.ProgressBar.Horizontal</item>
+ <item name="indeterminateProgressStyle">@style/Widget.Material.ProgressBar</item>
+ <item name="progressBarPadding">32dip</item>
+ <item name="itemPadding">8dip</item>
+ <item name="homeLayout">@layout/action_bar_home_material</item>
+ <item name="gravity">center_vertical</item>
+ <item name="contentInsetStart">16dp</item>
+ </style>
+
+ <style name="Widget.Material.ActionBar.Solid">
+ <item name="background">?attr/colorPrimary</item>
+ <item name="backgroundStacked">?attr/colorPrimary</item>
+ <item name="backgroundSplit">?attr/colorPrimary</item>
+ </style>
+
+ <style name="Widget.Material.ActionMode" parent="Widget.ActionMode">
+ <item name="titleTextStyle">@style/TextAppearance.Material.Widget.ActionMode.Title</item>
+ <item name="subtitleTextStyle">@style/TextAppearance.Material.Widget.ActionMode.Subtitle</item>
+ </style>
+
+ <style name="Widget.Material.FastScroll" parent="Widget.FastScroll">
+ <item name="thumbMinWidth">0dp</item>
+ <item name="thumbMinHeight">0dp</item>
+ </style>
+
+ <style name="Widget.Material.PreferenceFrameLayout">
+ <item name="borderTop">0dip</item>
+ <item name="borderBottom">@dimen/preference_fragment_padding_bottom</item>
+ <item name="borderLeft">?attr/preferenceFragmentPaddingSide</item>
+ <item name="borderRight">?attr/preferenceFragmentPaddingSide</item>
+ </style>
+
+ <style name="Widget.Material.MediaRouteButton">
+ <item name="background">?attr/selectableItemBackgroundBorderless</item>
+ <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_material</item>
+ <item name="minWidth">56dp</item>
+ <item name="minHeight">48dp</item>
+ <item name="focusable">true</item>
+ <item name="contentDescription">@string/media_route_button_content_description</item>
+ </style>
+
+ <!-- Light widget styles -->
+
+ <style name="Widget.Material.Light" parent="Widget.Material"/>
+ <style name="Widget.Material.Light.Button" parent="Widget.Material.Button"/>
+ <style name="Widget.Material.Light.Button.Small" parent="Widget.Material.Button.Small"/>
+ <style name="Widget.Material.Light.Button.Borderless" parent="Widget.Material.Button.Borderless"/>
+ <style name="Widget.Material.Light.Button.Borderless.Small" parent="Widget.Material.Button.Borderless.Small"/>
+ <style name="Widget.Material.Light.Button.Inset" parent="Widget.Material.Button.Inset"/>
+ <style name="Widget.Material.Light.Button.Toggle" parent="Widget.Material.Button.Toggle" />
+ <style name="Widget.Material.Light.ButtonBar" parent="Widget.Material.ButtonBar"/>
+ <style name="Widget.Material.Light.ButtonBar.AlertDialog" parent="Widget.Material.ButtonBar.AlertDialog"/>
+
+ <style name="Widget.Material.Light.SegmentedButton" parent="Widget.Material.SegmentedButton">
+ <item name="background">@drawable/btn_group_holo_light</item>
+ </style>
+
+ <style name="Widget.Material.Light.StackView" parent="Widget.Material.StackView"/>
+ <style name="Widget.Material.Light.TextView" parent="Widget.Material.TextView"/>
+ <style name="Widget.Material.Light.TextView.ListSeparator" parent="Widget.Material.TextView.ListSeparator"/>
+ <style name="Widget.Material.Light.TextView.SpinnerItem" parent="Widget.Material.TextView.SpinnerItem"/>
+ <style name="Widget.Material.Light.CheckedTextView" parent="Widget.Material.CheckedTextView"/>
+ <style name="Widget.Material.Light.TextSelectHandle" parent="Widget.Material.TextSelectHandle"/>
+ <style name="Widget.Material.Light.TextSuggestionsPopupWindow" parent="Widget.Material.TextSuggestionsPopupWindow"/>
+ <style name="Widget.Material.Light.AbsListView" parent="Widget.Material.AbsListView"/>
+ <style name="Widget.Material.Light.AutoCompleteTextView" parent="Widget.Material.AutoCompleteTextView" />
+ <style name="Widget.Material.Light.CompoundButton" parent="Widget.Material.CompoundButton"/>
+ <style name="Widget.Material.Light.CompoundButton.CheckBox" parent="Widget.Material.CompoundButton.CheckBox"/>
+ <style name="Widget.Material.Light.CompoundButton.RadioButton" parent="Widget.Material.CompoundButton.RadioButton"/>
+ <style name="Widget.Material.Light.CompoundButton.Star" parent="Widget.Material.CompoundButton.Star"/>
+ <style name="Widget.Material.Light.CompoundButton.Switch" parent="Widget.Material.CompoundButton.Switch" />
+ <style name="Widget.Material.Light.ListView.DropDown" parent="Widget.Material.ListView.DropDown"/>
+ <style name="Widget.Material.Light.EditText" parent="Widget.Material.EditText"/>
+ <style name="Widget.Material.Light.ExpandableListView" parent="Widget.Material.ExpandableListView"/>
+ <style name="Widget.Material.Light.ExpandableListView.White" parent="Widget.Material.ExpandableListView.White"/>
+ <style name="Widget.Material.Light.Gallery" parent="Widget.Material.Gallery"/>
+ <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>
+ </style>
+
+ <style name="Widget.Material.Light.NumberPicker" parent="Widget.Material.NumberPicker"/>
+
+ <style name="Widget.Material.Light.TimePicker" parent="Widget.Material.TimePicker">
+ <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
+ <item name="internalLayout">@layout/time_picker_holo</item>
+ <item name="disabledColor">@color/bright_foreground_disabled_material_light</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"/>
+ <style name="Widget.Material.Light.ListView.White" parent="Widget.Material.ListView.White"/>
+ <style name="Widget.Material.Light.PopupWindow" parent="Widget.Material.PopupWindow"/>
+ <style name="Widget.Material.Light.PopupWindow.ActionMode" parent="Widget.Material.PopupWindow.ActionMode"/>
+ <style name="Widget.Material.Light.ProgressBar" parent="Widget.Material.ProgressBar"/>
+ <style name="Widget.Material.Light.ProgressBar.Horizontal" parent="Widget.Material.ProgressBar.Horizontal"/>
+ <style name="Widget.Material.Light.ProgressBar.Small" parent="Widget.Material.ProgressBar.Small"/>
+ <style name="Widget.Material.Light.ProgressBar.Small.Title" parent="Widget.Material.ProgressBar.Small.Title"/>
+ <style name="Widget.Material.Light.ProgressBar.Large" parent="Widget.Material.ProgressBar.Large"/>
+ <style name="Widget.Material.Light.ProgressBar.Inverse" parent="Widget.Material.ProgressBar.Inverse"/>
+ <style name="Widget.Material.Light.ProgressBar.Small.Inverse" parent="Widget.Material.ProgressBar.Small.Inverse"/>
+ <style name="Widget.Material.Light.ProgressBar.Large.Inverse" parent="Widget.Material.ProgressBar.Large.Inverse"/>
+ <style name="Widget.Material.Light.SeekBar" parent="Widget.Material.SeekBar"/>
+ <style name="Widget.Material.Light.RatingBar" parent="Widget.Material.RatingBar" />
+
+ <style name="Widget.Material.Light.RatingBar.Indicator" parent="Widget.RatingBar.Indicator">
+ <item name="progressDrawable">@drawable/ratingbar_holo_light</item>
+ <item name="indeterminateDrawable">@drawable/ratingbar_holo_light</item>
+ <item name="minHeight">35dip</item>
+ <item name="maxHeight">35dip</item>
+ </style>
+
+ <style name="Widget.Material.Light.RatingBar.Small" parent="Widget.RatingBar.Small">
+ <item name="progressDrawable">@drawable/ratingbar_small_holo_light</item>
+ <item name="indeterminateDrawable">@drawable/ratingbar_small_holo_light</item>
+ <item name="minHeight">16dip</item>
+ <item name="maxHeight">16dip</item>
+ </style>
+
+ <style name="Widget.Material.Light.ScrollView" parent="Widget.Material.ScrollView"/>
+ <style name="Widget.Material.Light.HorizontalScrollView" parent="Widget.Material.HorizontalScrollView"/>
+ <style name="Widget.Material.Light.Spinner" parent="Widget.Material.Spinner" />
+ <style name="Widget.Material.Light.Spinner.DropDown" parent="Widget.Material.Spinner.DropDown"/>
+ <style name="Widget.Material.Light.Spinner.DropDown.ActionBar" parent="Widget.Material.Spinner.DropDown.ActionBar"/>
+ <style name="Widget.Material.Light.TabWidget" parent="Widget.Material.TabWidget"/>
+ <style name="Widget.Material.Light.WebTextView" parent="Widget.Material.WebTextView"/>
+ <style name="Widget.Material.Light.WebView" parent="Widget.Material.WebView"/>
+ <style name="Widget.Material.Light.DropDownItem" parent="Widget.Material.DropDownItem"/>
+ <style name="Widget.Material.Light.DropDownItem.Spinner" parent="Widget.Material.DropDownItem.Spinner"/>
+ <style name="Widget.Material.Light.KeyboardView" parent="Widget.Material.KeyboardView"/>
+ <style name="Widget.Material.Light.QuickContactBadge.WindowSmall" parent="Widget.Material.QuickContactBadge.WindowSmall"/>
+ <style name="Widget.Material.Light.QuickContactBadge.WindowMedium" parent="Widget.Material.QuickContactBadge.WindowMedium"/>
+ <style name="Widget.Material.Light.QuickContactBadge.WindowLarge" parent="Widget.Material.QuickContactBadge.WindowLarge"/>
+ <style name="Widget.Material.Light.QuickContactBadgeSmall.WindowSmall" parent="Widget.Material.QuickContactBadgeSmall.WindowSmall"/>
+ <style name="Widget.Material.Light.QuickContactBadgeSmall.WindowMedium" parent="Widget.Material.QuickContactBadgeSmall.WindowMedium"/>
+ <style name="Widget.Material.Light.QuickContactBadgeSmall.WindowLarge" parent="Widget.Material.QuickContactBadgeSmall.WindowLarge"/>
+ <style name="Widget.Material.Light.ListPopupWindow" parent="Widget.Material.ListPopupWindow"/>
+ <style name="Widget.Material.Light.PopupMenu" parent="Widget.Material.ListPopupWindow"/>
+ <style name="Widget.Material.Light.PopupMenu.Overflow" parent="Widget.Material.PopupMenu.Overflow"/>
+ <style name="Widget.Material.Light.ActionButton" parent="Widget.Material.ActionButton"/>
+ <style name="Widget.Material.Light.ActionButton.Overflow" parent="Widget.Material.ActionButton.Overflow"/>
+ <style name="Widget.Material.Light.Tab" parent="Widget.Material.Tab"/>
+ <style name="Widget.Material.Light.ActionBar.TabView" parent="Widget.Material.ActionBar.TabView"/>
+ <style name="Widget.Material.Light.ActionBar.TabBar" parent="Widget.Material.ActionBar.TabBar"/>
+ <style name="Widget.Material.Light.ActionBar.TabText" parent="Widget.Material.ActionBar.TabText"/>
+ <style name="Widget.Material.Light.ActionMode" parent="Widget.Material.ActionMode" />
+ <style name="Widget.Material.Light.ActionButton.CloseMode" parent="Widget.Material.ActionButton.CloseMode" />
+
+ <style name="Widget.Material.Light.ActionBar" parent="Widget.Material.ActionBar">
+ <item name="titleTextStyle">@style/TextAppearance.Material.Widget.ActionBar.Title</item>
+ <item name="subtitleTextStyle">@style/TextAppearance.Material.Widget.ActionBar.Subtitle</item>
+ <item name="background">@null</item>
+ <item name="backgroundStacked">@null</item>
+ <item name="backgroundSplit">@null</item>
+ <item name="homeAsUpIndicator">@drawable/ic_ab_back_material</item>
+ <item name="progressBarStyle">@style/Widget.Material.Light.ProgressBar.Horizontal</item>
+ <item name="indeterminateProgressStyle">@style/Widget.Material.Light.ProgressBar</item>
+ </style>
+
+ <style name="Widget.Material.Light.ActionBar.Solid">
+ <item name="background">?attr/colorPrimary</item>
+ <item name="backgroundStacked">?attr/colorPrimary</item>
+ <item name="backgroundSplit">?attr/colorPrimary</item>
+ </style>
+
+ <style name="Widget.Material.Light.FastScroll" parent="Widget.Material.FastScroll"/>
+ <style name="Widget.Material.Light.MediaRouteButton" parent="Widget.Material.MediaRouteButton" />
+
+ <!-- Animation Styles -->
+
+ <style name="Animation.Material" parent="Animation"/>
+ <style name="Animation.Material.Activity" parent="Animation.Activity"/>
+
+ <style name="Animation.Material.Dialog">
+ <item name="windowEnterAnimation">@anim/popup_enter_material</item>
+ <item name="windowExitAnimation">@anim/popup_exit_material</item>
+ </style>
+
+ <style name="Animation.Material.Popup">
+ <item name="windowEnterAnimation">@anim/popup_enter_material</item>
+ <item name="windowExitAnimation">@anim/popup_exit_material</item>
+ </style>
+
+ <!-- Dialog styles -->
+
+ <style name="AlertDialog.Material" parent="AlertDialog">
+ <item name="fullDark">@color/transparent</item>
+ <item name="topDark">@color/transparent</item>
+ <item name="centerDark">@color/transparent</item>
+ <item name="bottomDark">@color/transparent</item>
+ <item name="fullBright">@color/transparent</item>
+ <item name="topBright">@color/transparent</item>
+ <item name="centerBright">@color/transparent</item>
+ <item name="bottomBright">@color/transparent</item>
+ <item name="bottomMedium">@color/transparent</item>
+ <item name="centerMedium">@color/transparent</item>
+ <item name="layout">@layout/alert_dialog_material</item>
+ <item name="listLayout">@layout/select_dialog_material</item>
+ <item name="progressLayout">@layout/progress_dialog_material</item>
+ <item name="horizontalProgressLayout">@layout/alert_dialog_progress_material</item>
+ <item name="listItemLayout">@layout/select_dialog_item_material</item>
+ <item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_material</item>
+ <item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_material</item>
+ </style>
+
+ <style name="AlertDialog.Material.Light"/>
+
+ <!-- Window title -->
+ <style name="WindowTitleBackground.Material">
+ <item name="background">@null</item>
+ <item name="paddingStart">16dp</item>
+ <item name="paddingEnd">16dp</item>
+ <item name="paddingTop">16dp</item>
+ </style>
+
+ <style name="WindowTitle.Material">
+ <item name="singleLine">true</item>
+ <item name="textAppearance">@style/TextAppearance.Material.WindowTitle</item>
+ <item name="shadowRadius">0</item>
+ <item name="ellipsize">end</item>
+ <item name="textAlignment">viewStart</item>
+ </style>
+
+ <style name="DialogWindowTitle.Material">
+ <item name="maxLines">1</item>
+ <item name="scrollHorizontally">true</item>
+ <item name="textAppearance">@style/TextAppearance.Material.DialogWindowTitle</item>
+ </style>
+
+ <style name="DialogWindowTitle.Material.Light" />
+
+</resources>
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
deleted file mode 100644
index b5afc2f..0000000
--- a/core/res/res/values/styles_quantum.xml
+++ /dev/null
@@ -1,973 +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.
--->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Quantum themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see styles_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-<resources>
- <!-- Preference styles -->
- <eat-comment/>
-
- <style name="Preference.Quantum">
- <item name="layout">@layout/preference_quantum</item>
- </style>
-
- <style name="PreferenceFragment.Quantum">
- <item name="paddingStart">@dimen/preference_fragment_padding_side</item>
- <item name="paddingEnd">@dimen/preference_fragment_padding_side</item>
- </style>
-
- <style name="Preference.Quantum.Information">
- <item name="layout">@layout/preference_information_quantum</item>
- <item name="enabled">false</item>
- <item name="shouldDisableView">false</item>
- </style>
-
- <style name="Preference.Quantum.Category">
- <item name="layout">@layout/preference_category_quantum</item>
- <!-- The title should not dim if the category is disabled, instead only the preference children should dim. -->
- <item name="shouldDisableView">false</item>
- <item name="selectable">false</item>
- </style>
-
- <style name="Preference.Quantum.CheckBoxPreference">
- <item name="widgetLayout">@layout/preference_widget_checkbox</item>
- </style>
-
- <style name="Preference.Quantum.SwitchPreference">
- <item name="widgetLayout">@layout/preference_widget_switch</item>
- <item name="switchTextOn">@string/capital_on</item>
- <item name="switchTextOff">@string/capital_off</item>
- </style>
-
- <style name="Preference.Quantum.PreferenceScreen"/>
-
- <style name="Preference.Quantum.DialogPreference">
- <item name="positiveButtonText">@string/ok</item>
- <item name="negativeButtonText">@string/cancel</item>
- </style>
-
- <style name="Preference.Quantum.DialogPreference.YesNoPreference">
- <item name="positiveButtonText">@string/yes</item>
- <item name="negativeButtonText">@string/no</item>
- </style>
-
- <style name="Preference.Quantum.DialogPreference.EditTextPreference">
- <item name="dialogLayout">@layout/preference_dialog_edittext</item>
- </style>
-
- <style name="Preference.Quantum.RingtonePreference">
- <item name="ringtoneType">ringtone</item>
- <item name="showSilent">true</item>
- <item name="showDefault">true</item>
- </style>
-
- <!-- Begin Quantum theme styles -->
-
- <!-- Text styles -->
-
- <style name="TextAppearance.Quantum">
- <item name="textColor">?attr/textColorPrimary</item>
- <item name="textColorHint">?attr/textColorHint</item>
- <item name="textColorHighlight">?attr/textColorHighlight</item>
- <item name="textColorLink">?attr/textColorLink</item>
- <item name="textSize">@dimen/text_size_body_1_quantum</item>
- <item name="fontFamily">@string/font_family_body_1_quantum</item>
- </style>
-
- <style name="TextAppearance.Quantum.Display4">
- <item name="textSize">@dimen/text_size_display_4_quantum</item>
- <item name="fontFamily">@string/font_family_display_4_quantum</item>
- <item name="textColor">?attr/textColorSecondary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Display3">
- <item name="textSize">@dimen/text_size_display_3_quantum</item>
- <item name="fontFamily">@string/font_family_display_3_quantum</item>
- <item name="textColor">?attr/textColorSecondary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Display2">
- <item name="textSize">@dimen/text_size_display_2_quantum</item>
- <item name="fontFamily">@string/font_family_display_2_quantum</item>
- <item name="textColor">?attr/textColorSecondary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Display1">
- <item name="textSize">@dimen/text_size_display_1_quantum</item>
- <item name="fontFamily">@string/font_family_display_1_quantum</item>
- <item name="textColor">?attr/textColorSecondary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Headline">
- <item name="textSize">@dimen/text_size_headline_quantum</item>
- <item name="fontFamily">@string/font_family_headline_quantum</item>
- <item name="textColor">?attr/textColorPrimary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Title">
- <item name="textSize">@dimen/text_size_title_quantum</item>
- <item name="fontFamily">@string/font_family_title_quantum</item>
- <item name="textColor">?attr/textColorPrimary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Title.Inverse">
- <item name="textColor">?attr/textColorPrimaryInverse</item>
- <item name="textColorHint">?attr/textColorHintInverse</item>
- <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
- <item name="textColorLink">?attr/textColorLinkInverse</item>
- </style>
-
- <style name="TextAppearance.Quantum.Subhead">
- <item name="textSize">@dimen/text_size_subhead_quantum</item>
- <item name="fontFamily">@string/font_family_subhead_quantum</item>
- <item name="textColor">?attr/textColorPrimary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Subhead.Inverse">
- <item name="textColor">?attr/textColorSecondaryInverse</item>
- <item name="textColorHint">?attr/textColorHintInverse</item>
- <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
- <item name="textColorLink">?attr/textColorLinkInverse</item>
- </style>
-
- <style name="TextAppearance.Quantum.Body2">
- <item name="textSize">@dimen/text_size_body_2_quantum</item>
- <item name="fontFamily">@string/font_family_body_2_quantum</item>
- <item name="textColor">?attr/textColorPrimary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Body1">
- <item name="textSize">@dimen/text_size_body_1_quantum</item>
- <item name="fontFamily">@string/font_family_body_1_quantum</item>
- <item name="textColor">?attr/textColorPrimary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Caption">
- <item name="textSize">@dimen/text_size_caption_quantum</item>
- <item name="fontFamily">@string/font_family_caption_quantum</item>
- <item name="textColor">?attr/textColorSecondary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Menu">
- <item name="textSize">@dimen/text_size_menu_quantum</item>
- <item name="fontFamily">@string/font_family_menu_quantum</item>
- </style>
-
- <style name="TextAppearance.Quantum.Menu.Inverse">
- <item name="textColor">?attr/textColorSecondaryInverse</item>
- <item name="textColorHint">?attr/textColorHintInverse</item>
- <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
- <item name="textColorLink">?attr/textColorLinkInverse</item>
- </style>
-
- <style name="TextAppearance.Quantum.Button">
- <item name="textSize">@dimen/text_size_button_quantum</item>
- <item name="fontFamily">@string/font_family_button_quantum</item>
- <item name="textAllCaps">true</item>
- <item name="textColor">?attr/textColorPrimary</item>
- </style>
-
- <!-- Deprecated text styles -->
-
- <style name="TextAppearance.Quantum.Inverse">
- <item name="textColor">?attr/textColorPrimaryInverse</item>
- <item name="textColorHint">?attr/textColorHintInverse</item>
- <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
- <item name="textColorLink">?attr/textColorLinkInverse</item>
- </style>
-
- <style name="TextAppearance.Quantum.Large">
- <item name="textSize">@dimen/text_size_large_quantum</item>
- <item name="textColor">?attr/textColorPrimary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Large.Inverse">
- <item name="textColor">?attr/textColorPrimaryInverse</item>
- <item name="textColorHint">?attr/textColorHintInverse</item>
- <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
- <item name="textColorLink">?attr/textColorLinkInverse</item>
- </style>
-
- <style name="TextAppearance.Quantum.Medium">
- <item name="textSize">@dimen/text_size_medium_quantum</item>
- <item name="textColor">?attr/textColorSecondary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Medium.Inverse">
- <item name="textColor">?attr/textColorSecondaryInverse</item>
- <item name="textColorHint">?attr/textColorHintInverse</item>
- <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
- <item name="textColorLink">?attr/textColorLinkInverse</item>
- </style>
-
- <style name="TextAppearance.Quantum.Small">
- <item name="textSize">@dimen/text_size_small_quantum</item>
- <item name="textColor">?attr/textColorTertiary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Small.Inverse">
- <item name="textColor">?attr/textColorTertiaryInverse</item>
- <item name="textColorHint">?attr/textColorHintInverse</item>
- <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
- <item name="textColorLink">?attr/textColorLinkInverse</item>
- </style>
-
- <style name="TextAppearance.Quantum.SearchResult" />
- <style name="TextAppearance.Quantum.SearchResult.Title" parent="TextAppearance.Quantum.Title" />
- <style name="TextAppearance.Quantum.SearchResult.Subtitle" parent="TextAppearance.Quantum.Subhead" />
-
- <style name="TextAppearance.Quantum.Widget"/>
- <style name="TextAppearance.Quantum.Widget.Button" parent="TextAppearance.Quantum.Button" />
-
- <style name="TextAppearance.Quantum.Widget.EditText">
- <item name="textColor">?attr/textColorPrimaryInverse</item>
- <item name="textColorHint">?attr/textColorHintInverse</item>
- </style>
-
- <style name="TextAppearance.Quantum.Widget.Switch" parent="TextAppearance.Quantum.Button" />
-
- <style name="TextAppearance.Quantum.Widget.PopupMenu"/>
- <style name="TextAppearance.Quantum.Widget.PopupMenu.Large" parent="TextAppearance.Quantum.Menu" />
- <style name="TextAppearance.Quantum.Widget.PopupMenu.Small" parent="TextAppearance.Quantum.Menu" />
-
- <style name="TextAppearance.Quantum.Widget.DropDownHint" parent="TextAppearance.Quantum.Menu" />
-
- <style name="TextAppearance.Quantum.Widget.IconMenu.Item" parent="TextAppearance.Quantum.Small">
- <item name="textColor">?attr/textColorPrimary</item>
- </style>
-
- <style name="TextAppearance.Quantum.Widget.TabWidget" parent="TextAppearance.Quantum.Button" />
-
- <style name="TextAppearance.Quantum.Widget.TextView">
- <item name="textColor">?attr/textColorPrimaryDisableOnly</item>
- <item name="textColorHint">?attr/textColorHint</item>
- </style>
-
- <style name="TextAppearance.Quantum.Widget.TextView.PopupMenu" parent="TextAppearance.Quantum.Menu" />
- <style name="TextAppearance.Quantum.Widget.TextView.SpinnerItem" />
-
- <style name="TextAppearance.Quantum.Widget.DropDownItem">
- <item name="textColor">?attr/textColorPrimaryDisableOnly</item>
- </style>
-
- <style name="TextAppearance.Quantum.Widget.ActionMode"/>
- <style name="TextAppearance.Quantum.Widget.ActionMode.Title" parent="TextAppearance.Quantum.Title" />
- <style name="TextAppearance.Quantum.Widget.ActionMode.Title.Inverse" parent="TextAppearance.Quantum.Title.Inverse" />
- <style name="TextAppearance.Quantum.Widget.ActionMode.Subtitle" parent="TextAppearance.Quantum.Subhead" />
- <style name="TextAppearance.Quantum.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.Quantum.Subhead.Inverse" />
-
- <style name="TextAppearance.Quantum.Widget.ActionBar.Title" parent="TextAppearance.Quantum.Title" />
- <style name="TextAppearance.Quantum.Widget.ActionBar.Title.Inverse" parent="TextAppearance.Quantum.Title.Inverse" />
- <style name="TextAppearance.Quantum.Widget.ActionBar.Subtitle" parent="TextAppearance.Quantum.Subhead" />
- <style name="TextAppearance.Quantum.Widget.ActionBar.Subtitle.Inverse" parent="TextAppearance.Quantum.Subhead.Inverse" />
-
- <style name="TextAppearance.Quantum.Widget.ActionBar.Menu" parent="TextAppearance.Quantum.Menu">
- <item name="textColor">?attr/actionMenuTextColor</item>
- <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item>
- </style>
-
- <style name="TextAppearance.Quantum.Widget.ActionBar.Menu.Inverse" parent="TextAppearance.Quantum.Menu.Inverse">
- <item name="textColor">?attr/actionMenuTextColor</item>
- <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item>
- </style>
-
- <style name="TextAppearance.Quantum.WindowTitle" parent="TextAppearance.Quantum.Headline" />
- <style name="TextAppearance.Quantum.DialogWindowTitle" parent="TextAppearance.Quantum.Headline" />
-
- <style name="TextAppearance.Quantum.CalendarViewWeekDayView" parent="TextAppearance.Quantum.Small">
- <item name="textStyle">bold</item>
- <item name="textColor">#505050</item>
- </style>
-
- <style name="TextAppearance.Quantum.TimePicker.TimeLabel" parent="TextAppearance.Quantum">
- <item name="textSize">@dimen/timepicker_time_label_size</item>
- <item name="textColor">?attr/textColorSecondary</item>
- </style>
-
- <style name="TextAppearance.Quantum.TimePicker.AmPmLabel" parent="TextAppearance.Quantum">
- <item name="textSize">@dimen/timepicker_ampm_label_size</item>
- <item name="textAllCaps">true</item>
- <item name="textColor">?attr/textColorSecondary</item>
- <item name="textStyle">bold</item>
- </style>
-
- <style name="TextAppearance.StatusBar.Quantum" />
-
- <style name="TextAppearance.StatusBar.Quantum.EventContent">
- <item name="android:textColor">#90000000</item>
- <item name="android:textSize">@dimen/notification_text_size</item>
- </style>
-
- <style name="TextAppearance.StatusBar.Quantum.EventContent.Title">
- <item name="android:textColor">#DD000000</item>
- <item name="android:textSize">@dimen/notification_title_text_size</item>
- </style>
-
- <style name="TextAppearance.StatusBar.Quantum.EventContent.Line2">
- <item name="android:textSize">@dimen/notification_subtext_size</item>
- </style>
-
- <style name="TextAppearance.StatusBar.Quantum.EventContent.Info">
- <item name="android:textSize">@dimen/notification_subtext_size</item>
- </style>
-
- <style name="TextAppearance.StatusBar.Quantum.EventContent.Time">
- <item name="android:textSize">@dimen/notification_subtext_size</item>
- </style>
-
- <style name="TextAppearance.StatusBar.Quantum.EventContent.Emphasis">
- <item name="android:textColor">#66000000</item>
- </style>
-
- <style name="Widget.StatusBar.Quantum.ProgressBar" parent="Widget.Quantum.Light.ProgressBar.Horizontal">
- <item name="android:progressDrawable">@drawable/notification_quantum_media_progress</item>
- </style>
-
- <!-- Widget Styles -->
-
- <style name="Quantum"/>
- <style name="Quantum.Light"/>
- <style name="Widget.Quantum" parent="Widget" />
-
- <!-- Bordered ink button -->
- <style name="Widget.Quantum.Button" parent="Widget.Button">
- <item name="background">@drawable/btn_default_quantum</item>
- <item name="textAppearance">?attr/textAppearanceButton</item>
- <item name="textColor">?attr/textColorPrimary</item>
- <item name="minHeight">48dip</item>
- <item name="minWidth">88dip</item>
-
- <!-- TODO: Turn this back on when we support inset drawable outlines. -->
- <!-- <item name="stateListAnimator">@anim/button_state_list_anim_quantum</item> -->
- </style>
-
- <!-- Small bordered ink button -->
- <style name="Widget.Quantum.Button.Small">
- <item name="minHeight">48dip</item>
- <item name="minWidth">48dip</item>
- </style>
-
- <!-- Borderless ink button -->
- <style name="Widget.Quantum.Button.Borderless">
- <item name="background">@drawable/btn_borderless_quantum</item>
- <item name="stateListAnimator">@null</item>
- </style>
-
- <!-- Small borderless ink button -->
- <style name="Widget.Quantum.Button.Borderless.Small">
- <item name="minHeight">48dip</item>
- <item name="minWidth">48dip</item>
- </style>
-
- <style name="Widget.Quantum.Button.Inset">
- <item name="background">@drawable/button_inset</item>
- </style>
-
- <style name="Widget.Quantum.Button.Toggle">
- <item name="background">@drawable/btn_toggle_quantum</item>
- <item name="textOn">@string/capital_on</item>
- <item name="textOff">@string/capital_off</item>
- <item name="minHeight">48dip</item>
- </style>
-
- <style name="Widget.Quantum.ButtonBar">
- <item name="background">@null</item>
- </style>
-
- <style name="Widget.Quantum.ButtonBar.AlertDialog">
- <item name="background">@null</item>
- </style>
-
- <style name="Widget.Quantum.SegmentedButton" parent="SegmentedButton">
- <item name="background">@drawable/btn_group_holo_dark</item>
- </style>
-
- <style name="Widget.Quantum.StackView">
- <item name="resOutColor">@color/holo_blue_light</item>
- <item name="clickColor">@color/holo_blue_light</item>
- </style>
-
- <style name="Widget.Quantum.TextView" parent="Widget.TextView"/>
-
- <style name="Widget.Quantum.TextView.ListSeparator" parent="Widget.TextView.ListSeparator">
- <item name="background">@drawable/list_section_divider_quantum</item>
- <item name="textAllCaps">true</item>
- </style>
-
- <style name="Widget.Quantum.TextView.SpinnerItem" parent="Widget.TextView.SpinnerItem">
- <item name="textAppearance">@style/TextAppearance.Quantum.Widget.TextView.SpinnerItem</item>
- <item name="paddingStart">8dp</item>
- <item name="paddingEnd">8dp</item>
- </style>
-
- <style name="Widget.Quantum.CheckedTextView" parent="Widget.CheckedTextView" />
- <style name="Widget.Quantum.TextSelectHandle" parent="Widget.TextSelectHandle"/>
- <style name="Widget.Quantum.TextSuggestionsPopupWindow" parent="Widget.TextSuggestionsPopupWindow"/>
- <style name="Widget.Quantum.AbsListView" parent="Widget.AbsListView"/>
-
- <style name="Widget.Quantum.AutoCompleteTextView" parent="Widget.AutoCompleteTextView">
- <item name="dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
- <item name="popupBackground">@drawable/popup_background_quantum</item>
- </style>
-
- <style name="Widget.Quantum.CompoundButton" parent="Widget.CompoundButton"/>
-
- <style name="Widget.Quantum.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox">
- <item name="background">?attr/selectableItemBackgroundBorderless</item>
- </style>
-
- <style name="Widget.Quantum.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton">
- <item name="background">?attr/selectableItemBackgroundBorderless</item>
- </style>
-
- <style name="Widget.Quantum.CompoundButton.Star" parent="Widget.CompoundButton.Star">
- <item name="button">@drawable/btn_star_quantum</item>
- <item name="background">?attr/selectableItemBackgroundBorderless</item>
- </style>
-
- <style name="Widget.Quantum.CompoundButton.Switch">
- <item name="track">@drawable/switch_track_quantum</item>
- <item name="thumb">@drawable/switch_thumb_quantum_anim</item>
- <item name="splitTrack">true</item>
- <item name="switchTextAppearance">@style/TextAppearance.Quantum.Widget.Switch</item>
- <item name="textOn"></item>
- <item name="textOff"></item>
- <item name="switchMinWidth">4dip</item>
- <item name="switchPadding">4dip</item>
- <item name="background">?attr/selectableItemBackgroundBorderless</item>
- </style>
-
- <style name="Widget.Quantum.EditText" parent="Widget.EditText"/>
-
- <style name="Widget.Quantum.ExpandableListView" parent="Widget.Quantum.ListView">
- <item name="groupIndicator">@drawable/expander_group_quantum</item>
- <item name="indicatorLeft">?attr/expandableListPreferredItemIndicatorLeft</item>
- <item name="indicatorRight">?attr/expandableListPreferredItemIndicatorRight</item>
- <item name="childDivider">?attr/listDivider</item>
- </style>
-
- <style name="Widget.Quantum.ExpandableListView.White"/>
- <style name="Widget.Quantum.Gallery" parent="Widget.Gallery"/>
- <style name="Widget.Quantum.GestureOverlayView" parent="Widget.GestureOverlayView"/>
-
- <style name="Widget.Quantum.GridView" parent="Widget.GridView">
- <item name="android:listSelector">?attr/selectableItemBackground</item>
- </style>
-
- <style name="Widget.Quantum.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.Quantum.CalendarViewWeekDayView</item>
- </style>
-
- <style name="Widget.Quantum.ImageButton" parent="Widget.ImageButton">
- <item name="background">@drawable/btn_default_quantum</item>
- </style>
-
- <style name="Widget.Quantum.NumberPicker" parent="Widget.NumberPicker">
- <item name="internalLayout">@layout/number_picker_with_selector_wheel</item>
- <item name="solidColor">@color/transparent</item>
- <item name="selectionDivider">@drawable/numberpicker_selection_divider</item>
- <item name="selectionDividerHeight">2dip</item>
- <item name="selectionDividersDistance">48dip</item>
- <item name="internalMinWidth">64dip</item>
- <item name="internalMaxHeight">180dip</item>
- <item name="virtualButtonPressedDrawable">?attr/selectableItemBackground</item>
- </style>
-
- <style name="Widget.Quantum.TimePicker" parent="Widget.TimePicker">
- <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
- <item name="internalLayout">@layout/time_picker_holo</item>
- <item name="disabledColor">@color/bright_foreground_disabled_quantum_dark</item>
- <item name="headerSelectedTextColor">?attr/colorControlActivated</item>
- <item name="headerUnselectedTextColor">?attr/textColorPrimary</item>
- <item name="headerBackgroundColor">@color/transparent</item>
- <item name="numbersTextColor">?attr/textColorSecondary</item>
- <item name="numbersBackgroundColor">@color/transparent</item>
- <item name="amPmTextColor">?attr/textColorSecondary</item>
- <item name="amPmUnselectedBackgroundColor">@color/transparent</item>
- <item name="amPmSelectedBackgroundColor">?attr/colorControlActivated</item>
- <item name="numbersSelectorColor">?attr/colorControlActivated</item>
- </style>
-
- <style name="Widget.Quantum.DatePicker" parent="Widget.DatePicker">
- <item name="internalLayout">@layout/date_picker_holo</item>
- <item name="calendarViewShown">true</item>
- </style>
-
- <style name="Widget.Quantum.ActivityChooserView" parent="Widget.ActivityChooserView">
- <item name="background">@drawable/ab_share_pack_quantum</item>
- </style>
-
- <style name="Widget.Quantum.ImageWell" parent="Widget.ImageWell"/>
-
- <style name="Widget.Quantum.ListView" parent="Widget.ListView">
- <item name="divider">?attr/listDivider</item>
- <item name="listSelector">?attr/listChoiceBackgroundIndicator</item>
- </style>
-
- <style name="Widget.Quantum.ListView.DropDown"/>
- <style name="Widget.Quantum.ListView.White"/>
-
- <style name="Widget.Quantum.PopupWindow" parent="Widget.PopupWindow"/>
-
- <style name="Widget.Quantum.PopupWindow.ActionMode">
- <item name="popupBackground">@drawable/popup_background_quantum</item>
- <item name="popupAnimationStyle">@style/Animation.PopupWindow.ActionMode</item>
- </style>
-
- <style name="Widget.Quantum.ProgressBar" parent="Widget.ProgressBar">
- <item name="indeterminateDrawable">@drawable/progress_medium_quantum</item>
- </style>
-
- <style name="Widget.Quantum.ProgressBar.Inverse"/>
-
- <style name="Widget.Quantum.ProgressBar.Horizontal" parent="Widget.ProgressBar.Horizontal">
- <item name="progressDrawable">@drawable/progress_horizontal_quantum</item>
- <item name="indeterminateDrawable">@drawable/progress_indeterminate_horizontal_holo</item>
- <item name="minHeight">16dip</item>
- <item name="maxHeight">16dip</item>
- </style>
-
- <style name="Widget.Quantum.ProgressBar.Small" parent="Widget.ProgressBar.Small">
- <item name="indeterminateDrawable">@drawable/progress_small_quantum</item>
- </style>
-
- <style name="Widget.Quantum.ProgressBar.Small.Inverse"/>
- <style name="Widget.Quantum.ProgressBar.Small.Title"/>
-
- <style name="Widget.Quantum.ProgressBar.Large" parent="Widget.ProgressBar.Large">
- <item name="indeterminateDrawable">@drawable/progress_large_quantum</item>
- </style>
-
- <style name="Widget.Quantum.ProgressBar.Large.Inverse"/>
-
- <style name="Widget.Quantum.SeekBar">
- <item name="indeterminateOnly">false</item>
- <item name="progressDrawable">@drawable/scrubber_progress_horizontal_quantum</item>
- <item name="indeterminateDrawable">@drawable/scrubber_progress_horizontal_quantum</item>
- <item name="thumb">@drawable/scrubber_control_quantum_anim</item>
- <item name="splitTrack">true</item>
- <item name="focusable">true</item>
- <item name="paddingStart">16dip</item>
- <item name="paddingEnd">16dip</item>
- <item name="mirrorForRtl">true</item>
- <item name="background">?attr/selectableItemBackgroundBorderless</item>
- </style>
-
- <style name="Widget.Quantum.RatingBar" parent="Widget.RatingBar">
- <item name="progressDrawable">@drawable/ratingbar_full_quantum</item>
- <item name="indeterminateDrawable">@drawable/ratingbar_full_quantum</item>
- </style>
-
- <style name="Widget.Quantum.RatingBar.Indicator" parent="Widget.RatingBar.Indicator">
- <item name="progressDrawable">@drawable/ratingbar_holo_dark</item>
- <item name="indeterminateDrawable">@drawable/ratingbar_holo_dark</item>
- <item name="minHeight">35dip</item>
- <item name="maxHeight">35dip</item>
- </style>
-
- <style name="Widget.Quantum.RatingBar.Small" parent="Widget.RatingBar.Small">
- <item name="progressDrawable">@drawable/ratingbar_small_holo_dark</item>
- <item name="indeterminateDrawable">@drawable/ratingbar_small_holo_dark</item>
- <item name="minHeight">16dip</item>
- <item name="maxHeight">16dip</item>
- </style>
-
- <style name="Widget.Quantum.ScrollView" parent="Widget.ScrollView"/>
- <style name="Widget.Quantum.HorizontalScrollView" parent="Widget.HorizontalScrollView"/>
-
- <style name="Widget.Quantum.Spinner" parent="Widget.Spinner.DropDown">
- <item name="background">@drawable/spinner_background_quantum</item>
- <item name="dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
- <item name="popupBackground">@drawable/popup_background_quantum</item>
- <item name="dropDownVerticalOffset">0dip</item>
- <item name="dropDownHorizontalOffset">0dip</item>
- <item name="dropDownWidth">wrap_content</item>
- <item name="popupPromptView">@layout/simple_dropdown_hint</item>
- <item name="gravity">start|center_vertical</item>
- <item name="disableChildrenWhenDisabled">true</item>
- </style>
-
- <style name="Widget.Quantum.Spinner.DropDown"/>
-
- <style name="Widget.Quantum.Spinner.DropDown.ActionBar">
- <item name="background">@drawable/spinner_background_quantum</item>
- </style>
-
- <style name="Widget.Quantum.TabWidget" parent="Widget.TabWidget">
- <item name="tabStripLeft">@null</item>
- <item name="tabStripRight">@null</item>
- <item name="tabStripEnabled">false</item>
- <item name="divider">?attr/dividerVertical</item>
- <item name="showDividers">middle</item>
- <item name="dividerPadding">8dip</item>
- <item name="measureWithLargestChild">true</item>
- <item name="tabLayout">@layout/tab_indicator_quantum</item>
- </style>
-
- <style name="Widget.Quantum.Tab" parent="Widget.Quantum.ActionBar.TabView">
- <item name="background">@drawable/tab_indicator_quantum</item>
- <item name="layout_width">0dip</item>
- <item name="layout_weight">1</item>
- <item name="minWidth">80dip</item>
- </style>
-
- <style name="Widget.Quantum.TabText" parent="Widget.Quantum.ActionBar.TabText">
- <item name="maxWidth">180dip</item>
- </style>
-
- <style name="Widget.Quantum.WebTextView" parent="Widget.WebTextView"/>
-
- <style name="Widget.Quantum.WebView" parent="Widget.WebView"/>
-
- <style name="Widget.Quantum.DropDownItem" parent="Widget.DropDownItem">
- <item name="textAppearance">@style/TextAppearance.Quantum.Widget.DropDownItem</item>
- <item name="paddingStart">8dp</item>
- <item name="paddingEnd">8dp</item>
- </style>
-
- <style name="Widget.Quantum.DropDownItem.Spinner"/>
-
- <style name="Widget.Quantum.KeyboardView" parent="Widget.KeyboardView"/>
- <style name="Widget.Quantum.QuickContactBadge.WindowSmall" parent="Widget.QuickContactBadge.WindowSmall"/>
- <style name="Widget.Quantum.QuickContactBadge.WindowMedium" parent="Widget.QuickContactBadge.WindowMedium"/>
- <style name="Widget.Quantum.QuickContactBadge.WindowLarge" parent="Widget.QuickContactBadge.WindowLarge"/>
- <style name="Widget.Quantum.QuickContactBadgeSmall.WindowSmall" parent="Widget.QuickContactBadgeSmall.WindowSmall"/>
- <style name="Widget.Quantum.QuickContactBadgeSmall.WindowMedium" parent="Widget.QuickContactBadgeSmall.WindowMedium"/>
- <style name="Widget.Quantum.QuickContactBadgeSmall.WindowLarge" parent="Widget.QuickContactBadgeSmall.WindowLarge"/>
-
- <style name="Widget.Quantum.ListPopupWindow" parent="Widget.ListPopupWindow">
- <item name="dropDownSelector">?attr/listChoiceBackgroundIndicator</item>
- <item name="popupBackground">@drawable/popup_background_quantum</item>
- <item name="popupAnimationStyle">@style/Animation.Quantum.Popup</item>
- <item name="dropDownVerticalOffset">0dip</item>
- <item name="dropDownHorizontalOffset">0dip</item>
- <item name="dropDownWidth">wrap_content</item>
- </style>
-
- <style name="Widget.Quantum.PopupMenu" parent="Widget.Quantum.ListPopupWindow"/>
-
- <style name="Widget.Quantum.PopupMenu.Overflow">
- <item name="overlapAnchor">true</item>
- </style>
-
- <style name="Widget.Quantum.ActionButton" parent="Widget.ActionButton">
- <item name="minWidth">@dimen/action_button_min_width_quantum</item>
- <item name="minHeight">@dimen/action_button_min_height_quantum</item>
- <item name="gravity">center</item>
- <item name="scaleType">center</item>
- <item name="maxLines">2</item>
- </style>
-
- <style name="Widget.Quantum.ActionButton.CloseMode">
- <item name="background">@drawable/btn_cab_done_quantum</item>
- </style>
-
- <style name="Widget.Quantum.ActionButton.Overflow">
- <item name="src">@drawable/ic_menu_moreoverflow_quantum</item>
- <item name="background">?attr/actionBarItemBackground</item>
- <item name="contentDescription">@string/action_menu_overflow_description</item>
- <item name="minWidth">@dimen/action_overflow_min_width_quantum</item>
- <item name="minHeight">@dimen/action_button_min_height_quantum</item>
- <item name="scaleType">center</item>
- </style>
-
- <style name="Widget.Quantum.ActionBar.TabView" parent="Widget.ActionBar.TabView">
- <item name="background">@drawable/tab_indicator_quantum</item>
- <item name="paddingStart">16dip</item>
- <item name="paddingEnd">16dip</item>
- </style>
-
- <style name="Widget.Quantum.ActionBar.TabBar" parent="Widget.ActionBar.TabBar">
- <item name="divider">?attr/actionBarDivider</item>
- <item name="showDividers">middle</item>
- <item name="dividerPadding">12dip</item>
- </style>
-
- <style name="Widget.Quantum.ActionBar.TabText" parent="Widget.ActionBar.TabText">
- <item name="textAppearance">@style/TextAppearance.Quantum.Medium</item>
- <item name="textColor">?attr/textColorPrimary</item>
- <item name="textSize">12sp</item>
- <item name="textStyle">bold</item>
- <item name="textAllCaps">true</item>
- <item name="ellipsize">marquee</item>
- <item name="maxLines">2</item>
- </style>
-
- <style name="Widget.Quantum.ActionBar" parent="Widget.ActionBar">
- <item name="background">@null</item>
- <item name="backgroundStacked">@null</item>
- <item name="backgroundSplit">@null</item>
- <item name="displayOptions">showTitle</item>
- <item name="divider">?attr/dividerVertical</item>
- <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
- <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
- <item name="progressBarStyle">@style/Widget.Quantum.ProgressBar.Horizontal</item>
- <item name="indeterminateProgressStyle">@style/Widget.Quantum.ProgressBar</item>
- <item name="progressBarPadding">32dip</item>
- <item name="itemPadding">8dip</item>
- <item name="homeLayout">@layout/action_bar_home_quantum</item>
- <item name="gravity">center_vertical</item>
- <item name="contentInsetStart">16dp</item>
- </style>
-
- <style name="Widget.Quantum.ActionBar.Solid">
- <item name="background">?attr/colorPrimary</item>
- <item name="backgroundStacked">?attr/colorPrimary</item>
- <item name="backgroundSplit">?attr/colorPrimary</item>
- </style>
-
- <style name="Widget.Quantum.ActionMode" parent="Widget.ActionMode">
- <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionMode.Title</item>
- <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionMode.Subtitle</item>
- </style>
-
- <style name="Widget.Quantum.FastScroll" parent="Widget.FastScroll">
- <item name="thumbMinWidth">0dp</item>
- <item name="thumbMinHeight">0dp</item>
- </style>
-
- <style name="Widget.Quantum.PreferenceFrameLayout">
- <item name="borderTop">0dip</item>
- <item name="borderBottom">@dimen/preference_fragment_padding_bottom</item>
- <item name="borderLeft">?attr/preferenceFragmentPaddingSide</item>
- <item name="borderRight">?attr/preferenceFragmentPaddingSide</item>
- </style>
-
- <style name="Widget.Quantum.MediaRouteButton">
- <item name="background">?attr/selectableItemBackgroundBorderless</item>
- <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_quantum</item>
- <item name="minWidth">56dp</item>
- <item name="minHeight">48dp</item>
- <item name="focusable">true</item>
- <item name="contentDescription">@string/media_route_button_content_description</item>
- </style>
-
- <!-- Light widget styles -->
-
- <style name="Widget.Quantum.Light" parent="Widget.Quantum"/>
- <style name="Widget.Quantum.Light.Button" parent="Widget.Quantum.Button"/>
- <style name="Widget.Quantum.Light.Button.Small" parent="Widget.Quantum.Button.Small"/>
- <style name="Widget.Quantum.Light.Button.Borderless" parent="Widget.Quantum.Button.Borderless"/>
- <style name="Widget.Quantum.Light.Button.Borderless.Small" parent="Widget.Quantum.Button.Borderless.Small"/>
- <style name="Widget.Quantum.Light.Button.Inset" parent="Widget.Quantum.Button.Inset"/>
- <style name="Widget.Quantum.Light.Button.Toggle" parent="Widget.Quantum.Button.Toggle" />
- <style name="Widget.Quantum.Light.ButtonBar" parent="Widget.Quantum.ButtonBar"/>
- <style name="Widget.Quantum.Light.ButtonBar.AlertDialog" parent="Widget.Quantum.ButtonBar.AlertDialog"/>
-
- <style name="Widget.Quantum.Light.SegmentedButton" parent="Widget.Quantum.SegmentedButton">
- <item name="background">@drawable/btn_group_holo_light</item>
- </style>
-
- <style name="Widget.Quantum.Light.StackView" parent="Widget.Quantum.StackView"/>
- <style name="Widget.Quantum.Light.TextView" parent="Widget.Quantum.TextView"/>
- <style name="Widget.Quantum.Light.TextView.ListSeparator" parent="Widget.Quantum.TextView.ListSeparator"/>
- <style name="Widget.Quantum.Light.TextView.SpinnerItem" parent="Widget.Quantum.TextView.SpinnerItem"/>
- <style name="Widget.Quantum.Light.CheckedTextView" parent="Widget.Quantum.CheckedTextView"/>
- <style name="Widget.Quantum.Light.TextSelectHandle" parent="Widget.Quantum.TextSelectHandle"/>
- <style name="Widget.Quantum.Light.TextSuggestionsPopupWindow" parent="Widget.Quantum.TextSuggestionsPopupWindow"/>
- <style name="Widget.Quantum.Light.AbsListView" parent="Widget.Quantum.AbsListView"/>
- <style name="Widget.Quantum.Light.AutoCompleteTextView" parent="Widget.Quantum.AutoCompleteTextView" />
- <style name="Widget.Quantum.Light.CompoundButton" parent="Widget.Quantum.CompoundButton"/>
- <style name="Widget.Quantum.Light.CompoundButton.CheckBox" parent="Widget.Quantum.CompoundButton.CheckBox"/>
- <style name="Widget.Quantum.Light.CompoundButton.RadioButton" parent="Widget.Quantum.CompoundButton.RadioButton"/>
- <style name="Widget.Quantum.Light.CompoundButton.Star" parent="Widget.Quantum.CompoundButton.Star"/>
- <style name="Widget.Quantum.Light.CompoundButton.Switch" parent="Widget.Quantum.CompoundButton.Switch" />
- <style name="Widget.Quantum.Light.ListView.DropDown" parent="Widget.Quantum.ListView.DropDown"/>
- <style name="Widget.Quantum.Light.EditText" parent="Widget.Quantum.EditText"/>
- <style name="Widget.Quantum.Light.ExpandableListView" parent="Widget.Quantum.ExpandableListView"/>
- <style name="Widget.Quantum.Light.ExpandableListView.White" parent="Widget.Quantum.ExpandableListView.White"/>
- <style name="Widget.Quantum.Light.Gallery" parent="Widget.Quantum.Gallery"/>
- <style name="Widget.Quantum.Light.GestureOverlayView" parent="Widget.Quantum.GestureOverlayView"/>
- <style name="Widget.Quantum.Light.GridView" parent="Widget.Quantum.GridView"/>
- <style name="Widget.Quantum.Light.ImageButton" parent="Widget.Quantum.ImageButton"/>
-
- <style name="Widget.Quantum.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.Quantum.CalendarViewWeekDayView</item>
- </style>
-
- <style name="Widget.Quantum.Light.NumberPicker" parent="Widget.Quantum.NumberPicker"/>
-
- <style name="Widget.Quantum.Light.TimePicker" parent="Widget.Quantum.TimePicker">
- <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
- <item name="internalLayout">@layout/time_picker_holo</item>
- <item name="disabledColor">@color/bright_foreground_disabled_quantum_light</item>
- </style>
-
- <style name="Widget.Quantum.Light.DatePicker" parent="Widget.Quantum.DatePicker"/>
- <style name="Widget.Quantum.Light.ActivityChooserView" parent="Widget.Quantum.ActivityChooserView" />
- <style name="Widget.Quantum.Light.ImageWell" parent="Widget.Quantum.ImageWell"/>
- <style name="Widget.Quantum.Light.ListView" parent="Widget.Quantum.ListView"/>
- <style name="Widget.Quantum.Light.ListView.White" parent="Widget.Quantum.ListView.White"/>
- <style name="Widget.Quantum.Light.PopupWindow" parent="Widget.Quantum.PopupWindow"/>
- <style name="Widget.Quantum.Light.PopupWindow.ActionMode" parent="Widget.Quantum.PopupWindow.ActionMode"/>
- <style name="Widget.Quantum.Light.ProgressBar" parent="Widget.Quantum.ProgressBar"/>
- <style name="Widget.Quantum.Light.ProgressBar.Horizontal" parent="Widget.Quantum.ProgressBar.Horizontal"/>
- <style name="Widget.Quantum.Light.ProgressBar.Small" parent="Widget.Quantum.ProgressBar.Small"/>
- <style name="Widget.Quantum.Light.ProgressBar.Small.Title" parent="Widget.Quantum.ProgressBar.Small.Title"/>
- <style name="Widget.Quantum.Light.ProgressBar.Large" parent="Widget.Quantum.ProgressBar.Large"/>
- <style name="Widget.Quantum.Light.ProgressBar.Inverse" parent="Widget.Quantum.ProgressBar.Inverse"/>
- <style name="Widget.Quantum.Light.ProgressBar.Small.Inverse" parent="Widget.Quantum.ProgressBar.Small.Inverse"/>
- <style name="Widget.Quantum.Light.ProgressBar.Large.Inverse" parent="Widget.Quantum.ProgressBar.Large.Inverse"/>
- <style name="Widget.Quantum.Light.SeekBar" parent="Widget.Quantum.SeekBar"/>
- <style name="Widget.Quantum.Light.RatingBar" parent="Widget.Quantum.RatingBar" />
-
- <style name="Widget.Quantum.Light.RatingBar.Indicator" parent="Widget.RatingBar.Indicator">
- <item name="progressDrawable">@drawable/ratingbar_holo_light</item>
- <item name="indeterminateDrawable">@drawable/ratingbar_holo_light</item>
- <item name="minHeight">35dip</item>
- <item name="maxHeight">35dip</item>
- </style>
-
- <style name="Widget.Quantum.Light.RatingBar.Small" parent="Widget.RatingBar.Small">
- <item name="progressDrawable">@drawable/ratingbar_small_holo_light</item>
- <item name="indeterminateDrawable">@drawable/ratingbar_small_holo_light</item>
- <item name="minHeight">16dip</item>
- <item name="maxHeight">16dip</item>
- </style>
-
- <style name="Widget.Quantum.Light.ScrollView" parent="Widget.Quantum.ScrollView"/>
- <style name="Widget.Quantum.Light.HorizontalScrollView" parent="Widget.Quantum.HorizontalScrollView"/>
- <style name="Widget.Quantum.Light.Spinner" parent="Widget.Quantum.Spinner" />
- <style name="Widget.Quantum.Light.Spinner.DropDown" parent="Widget.Quantum.Spinner.DropDown"/>
- <style name="Widget.Quantum.Light.Spinner.DropDown.ActionBar" parent="Widget.Quantum.Spinner.DropDown.ActionBar"/>
- <style name="Widget.Quantum.Light.TabWidget" parent="Widget.Quantum.TabWidget"/>
- <style name="Widget.Quantum.Light.WebTextView" parent="Widget.Quantum.WebTextView"/>
- <style name="Widget.Quantum.Light.WebView" parent="Widget.Quantum.WebView"/>
- <style name="Widget.Quantum.Light.DropDownItem" parent="Widget.Quantum.DropDownItem"/>
- <style name="Widget.Quantum.Light.DropDownItem.Spinner" parent="Widget.Quantum.DropDownItem.Spinner"/>
- <style name="Widget.Quantum.Light.KeyboardView" parent="Widget.Quantum.KeyboardView"/>
- <style name="Widget.Quantum.Light.QuickContactBadge.WindowSmall" parent="Widget.Quantum.QuickContactBadge.WindowSmall"/>
- <style name="Widget.Quantum.Light.QuickContactBadge.WindowMedium" parent="Widget.Quantum.QuickContactBadge.WindowMedium"/>
- <style name="Widget.Quantum.Light.QuickContactBadge.WindowLarge" parent="Widget.Quantum.QuickContactBadge.WindowLarge"/>
- <style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowSmall" parent="Widget.Quantum.QuickContactBadgeSmall.WindowSmall"/>
- <style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowMedium" parent="Widget.Quantum.QuickContactBadgeSmall.WindowMedium"/>
- <style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowLarge" parent="Widget.Quantum.QuickContactBadgeSmall.WindowLarge"/>
- <style name="Widget.Quantum.Light.ListPopupWindow" parent="Widget.Quantum.ListPopupWindow"/>
- <style name="Widget.Quantum.Light.PopupMenu" parent="Widget.Quantum.ListPopupWindow"/>
- <style name="Widget.Quantum.Light.PopupMenu.Overflow" parent="Widget.Quantum.PopupMenu.Overflow"/>
- <style name="Widget.Quantum.Light.ActionButton" parent="Widget.Quantum.ActionButton"/>
- <style name="Widget.Quantum.Light.ActionButton.Overflow" parent="Widget.Quantum.ActionButton.Overflow"/>
- <style name="Widget.Quantum.Light.Tab" parent="Widget.Quantum.Tab"/>
- <style name="Widget.Quantum.Light.ActionBar.TabView" parent="Widget.Quantum.ActionBar.TabView"/>
- <style name="Widget.Quantum.Light.ActionBar.TabBar" parent="Widget.Quantum.ActionBar.TabBar"/>
- <style name="Widget.Quantum.Light.ActionBar.TabText" parent="Widget.Quantum.ActionBar.TabText"/>
- <style name="Widget.Quantum.Light.ActionMode" parent="Widget.Quantum.ActionMode" />
- <style name="Widget.Quantum.Light.ActionButton.CloseMode" parent="Widget.Quantum.ActionButton.CloseMode" />
-
- <style name="Widget.Quantum.Light.ActionBar" parent="Widget.Quantum.ActionBar">
- <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
- <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
- <item name="background">@null</item>
- <item name="backgroundStacked">@null</item>
- <item name="backgroundSplit">@null</item>
- <item name="homeAsUpIndicator">@drawable/ic_ab_back_quantum</item>
- <item name="progressBarStyle">@style/Widget.Quantum.Light.ProgressBar.Horizontal</item>
- <item name="indeterminateProgressStyle">@style/Widget.Quantum.Light.ProgressBar</item>
- </style>
-
- <style name="Widget.Quantum.Light.ActionBar.Solid">
- <item name="background">?attr/colorPrimary</item>
- <item name="backgroundStacked">?attr/colorPrimary</item>
- <item name="backgroundSplit">?attr/colorPrimary</item>
- </style>
-
- <style name="Widget.Quantum.Light.FastScroll" parent="Widget.Quantum.FastScroll"/>
- <style name="Widget.Quantum.Light.MediaRouteButton" parent="Widget.Quantum.MediaRouteButton" />
-
- <!-- Animation Styles -->
-
- <style name="Animation.Quantum" parent="Animation"/>
- <style name="Animation.Quantum.Activity" parent="Animation.Activity"/>
-
- <style name="Animation.Quantum.Dialog">
- <item name="windowEnterAnimation">@anim/popup_enter_quantum</item>
- <item name="windowExitAnimation">@anim/popup_exit_quantum</item>
- </style>
-
- <style name="Animation.Quantum.Popup">
- <item name="windowEnterAnimation">@anim/popup_enter_quantum</item>
- <item name="windowExitAnimation">@anim/popup_exit_quantum</item>
- </style>
-
- <!-- Dialog styles -->
-
- <style name="AlertDialog.Quantum" parent="AlertDialog">
- <item name="fullDark">@color/transparent</item>
- <item name="topDark">@color/transparent</item>
- <item name="centerDark">@color/transparent</item>
- <item name="bottomDark">@color/transparent</item>
- <item name="fullBright">@color/transparent</item>
- <item name="topBright">@color/transparent</item>
- <item name="centerBright">@color/transparent</item>
- <item name="bottomBright">@color/transparent</item>
- <item name="bottomMedium">@color/transparent</item>
- <item name="centerMedium">@color/transparent</item>
- <item name="layout">@layout/alert_dialog_quantum</item>
- <item name="listLayout">@layout/select_dialog_quantum</item>
- <item name="progressLayout">@layout/progress_dialog_quantum</item>
- <item name="horizontalProgressLayout">@layout/alert_dialog_progress_quantum</item>
- <item name="listItemLayout">@layout/select_dialog_item_quantum</item>
- <item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_quantum</item>
- <item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_quantum</item>
- </style>
-
- <style name="AlertDialog.Quantum.Light"/>
-
- <!-- Window title -->
- <style name="WindowTitleBackground.Quantum">
- <item name="background">@null</item>
- </style>
-
- <style name="WindowTitle.Quantum">
- <item name="singleLine">true</item>
- <item name="textAppearance">@style/TextAppearance.Quantum.WindowTitle</item>
- <item name="shadowRadius">0</item>
- </style>
-
- <style name="DialogWindowTitle.Quantum">
- <item name="maxLines">1</item>
- <item name="scrollHorizontally">true</item>
- <item name="textAppearance">@style/TextAppearance.Quantum.DialogWindowTitle</item>
- </style>
-
- <style name="DialogWindowTitle.Quantum.Light">
- <item name="textAppearance">@style/TextAppearance.Quantum.DialogWindowTitle</item>
- </style>
-
-</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7e3394b..5f4553b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -347,7 +347,7 @@
<java-symbol type="dimen" name="notification_title_text_size" />
<java-symbol type="dimen" name="notification_subtext_size" />
<java-symbol type="dimen" name="immersive_mode_cling_width" />
- <java-symbol type="dimen" name="notification_quantum_rounded_rect_radius" />
+ <java-symbol type="dimen" name="notification_material_rounded_rect_radius" />
<java-symbol type="string" name="add_account_button_label" />
<java-symbol type="string" name="addToDictionary" />
@@ -999,6 +999,7 @@
<java-symbol type="array" name="config_sameNamedOperatorConsideredRoaming" />
<java-symbol type="array" name="config_callBarringMMI" />
<java-symbol type="array" name="config_globalActionsList" />
+ <java-symbol type="array" name="config_telephonyHardware" />
<java-symbol type="drawable" name="default_wallpaper" />
<java-symbol type="drawable" name="indicator_input_error" />
@@ -1018,11 +1019,11 @@
<java-symbol type="drawable" name="text_edit_side_paste_window" />
<java-symbol type="drawable" name="text_edit_paste_window" />
<java-symbol type="drawable" name="btn_check_off" />
- <java-symbol type="drawable" name="btn_code_lock_default_qntm_alpha" />
- <java-symbol type="drawable" name="btn_code_lock_touched_qntm_alpha" />
- <java-symbol type="drawable" name="indicator_code_lock_point_area_default_qntm_alpha" />
- <java-symbol type="drawable" name="indicator_code_lock_point_area_qntm_alpha" />
- <java-symbol type="drawable" name="indicator_code_lock_drag_direction_up_qntm_alpha" />
+ <java-symbol type="drawable" name="btn_code_lock_default_mtrl_alpha" />
+ <java-symbol type="drawable" name="btn_code_lock_touched_mtrl_alpha" />
+ <java-symbol type="drawable" name="indicator_code_lock_point_area_default_mtrl_alpha" />
+ <java-symbol type="drawable" name="indicator_code_lock_point_area_mtrl_alpha" />
+ <java-symbol type="drawable" name="indicator_code_lock_drag_direction_up_mtrl_alpha" />
<java-symbol type="color" name="lock_pattern_view_regular_color" />
<java-symbol type="color" name="lock_pattern_view_success_color" />
<java-symbol type="color" name="lock_pattern_view_error_color" />
@@ -1122,6 +1123,15 @@
<java-symbol type="drawable" name="ic_corp_badge" />
<java-symbol type="drawable" name="ic_corp_icon_badge" />
+ <java-symbol type="drawable" name="sim_light_blue" />
+ <java-symbol type="drawable" name="sim_light_green" />
+ <java-symbol type="drawable" name="sim_light_orange" />
+ <java-symbol type="drawable" name="sim_light_purple" />
+ <java-symbol type="drawable" name="sim_dark_blue" />
+ <java-symbol type="drawable" name="sim_dark_green" />
+ <java-symbol type="drawable" name="sim_dark_orange" />
+ <java-symbol type="drawable" name="sim_dark_purple" />
+
<java-symbol type="layout" name="action_bar_home" />
<java-symbol type="layout" name="action_bar_title_item" />
<java-symbol type="layout" name="action_menu_item_layout" />
@@ -1462,6 +1472,7 @@
<java-symbol type="bool" name="config_animateScreenLights" />
<java-symbol type="bool" name="config_automatic_brightness_available" />
<java-symbol type="bool" name="config_enableFusedLocationOverlay" />
+ <java-symbol type="bool" name="config_enableHardwareFlpOverlay" />
<java-symbol type="bool" name="config_enableGeocoderOverlay" />
<java-symbol type="bool" name="config_enableGeofenceOverlay" />
<java-symbol type="bool" name="config_enableNetworkLocationOverlay" />
@@ -1509,7 +1520,7 @@
<java-symbol type="integer" name="config_defaultNotificationLedOn" />
<java-symbol type="integer" name="config_deskDockKeepsScreenOn" />
<java-symbol type="integer" name="config_lightSensorWarmupTime" />
- <java-symbol type="integer" name="config_lowBatteryCloseWarningLevel" />
+ <java-symbol type="integer" name="config_lowBatteryCloseWarningBump" />
<java-symbol type="integer" name="config_lowBatteryWarningLevel" />
<java-symbol type="integer" name="config_networkPolicyDefaultWarning" />
<java-symbol type="integer" name="config_networkTransitionTimeout" />
@@ -1518,6 +1529,7 @@
<java-symbol type="integer" name="config_notificationsBatteryLedOn" />
<java-symbol type="integer" name="config_notificationsBatteryLowARGB" />
<java-symbol type="integer" name="config_notificationsBatteryMediumARGB" />
+ <java-symbol type="integer" name="config_notificationServiceArchiveSize" />
<java-symbol type="integer" name="config_radioScanningTimeout" />
<java-symbol type="integer" name="config_screenBrightnessSettingMinimum" />
<java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
@@ -1552,6 +1564,7 @@
<java-symbol type="string" name="chooser_wallpaper" />
<java-symbol type="string" name="config_datause_iface" />
<java-symbol type="string" name="config_fusedLocationProviderPackageName" />
+ <java-symbol type="string" name="config_hardwareFlpPackageName" />
<java-symbol type="string" name="config_geocoderProviderPackageName" />
<java-symbol type="string" name="config_geofenceProviderPackageName" />
<java-symbol type="string" name="config_networkLocationProviderPackageName" />
@@ -1658,27 +1671,26 @@
<java-symbol type="integer" name="config_maxResolverActivityColumns" />
<java-symbol type="array" name="config_notificationSignalExtractors" />
- <java-symbol type="layout" name="notification_quantum_action" />
- <java-symbol type="layout" name="notification_quantum_action_list" />
- <java-symbol type="layout" name="notification_quantum_action_tombstone" />
- <java-symbol type="layout" name="notification_template_quantum_base" />
- <java-symbol type="layout" name="notification_template_quantum_big_base" />
- <java-symbol type="layout" name="notification_template_quantum_big_picture" />
- <java-symbol type="layout" name="notification_template_quantum_big_text" />
- <java-symbol type="layout" name="notification_template_quantum_inbox" />
- <java-symbol type="layout" name="notification_template_quantum_media" />
- <java-symbol type="layout" name="notification_template_quantum_big_media" />
+ <java-symbol type="layout" name="notification_material_action" />
+ <java-symbol type="layout" name="notification_material_action_list" />
+ <java-symbol type="layout" name="notification_material_action_tombstone" />
+ <java-symbol type="layout" name="notification_template_material_base" />
+ <java-symbol type="layout" name="notification_template_material_big_base" />
+ <java-symbol type="layout" name="notification_template_material_big_picture" />
+ <java-symbol type="layout" name="notification_template_material_big_text" />
+ <java-symbol type="layout" name="notification_template_material_inbox" />
+ <java-symbol type="layout" name="notification_template_material_media" />
+ <java-symbol type="layout" name="notification_template_material_big_media" />
<java-symbol type="layout" name="notification_template_icon_group" />
- <java-symbol type="layout" name="notification_quantum_media_action" />
+ <java-symbol type="layout" name="notification_material_media_action" />
<java-symbol type="color" name="notification_action_legacy_color_filter" />
<java-symbol type="color" name="notification_icon_bg_color" />
<java-symbol type="drawable" name="notification_icon_legacy_bg" />
<java-symbol type="drawable" name="notification_icon_legacy_bg_inset" />
- <java-symbol type="drawable" name="notification_quantum_bg_dim" />
- <java-symbol type="drawable" name="notification_quantum_bg" />
- <java-symbol type="drawable" name="notification_quantum_media_progress" />
+ <java-symbol type="drawable" name="notification_material_bg_dim" />
+ <java-symbol type="drawable" name="notification_material_bg" />
+ <java-symbol type="drawable" name="notification_material_media_progress" />
<java-symbol type="color" name="notification_media_action_bg" />
- <java-symbol type="color" name="notification_media_info_bg" />
<java-symbol type="color" name="notification_media_progress" />
<java-symbol type="id" name="media_action_area" />
@@ -1865,7 +1877,7 @@
<java-symbol type="string" name="timepicker_transition_end_radius_multiplier" />
<java-symbol type="array" name="config_clockTickVibePattern" />
- <!-- From various Quantum changes -->
+ <!-- From various Material changes -->
<java-symbol type="attr" name="toolbarStyle" />
<java-symbol type="attr" name="titleTextAppearance" />
<java-symbol type="attr" name="subtitleTextAppearance" />
@@ -1874,12 +1886,13 @@
<java-symbol type="id" name="icon_frame" />
<java-symbol type="style" name="Animation.VolumePanel" />
<java-symbol type="transition" name="no_transition" />
- <java-symbol type="color" name="timepicker_default_text_color_quantum" />
- <java-symbol type="color" name="timepicker_default_disabled_color_quantum" />
- <java-symbol type="color" name="timepicker_default_ampm_unselected_background_color_quantum" />
- <java-symbol type="color" name="timepicker_default_ampm_selected_background_color_quantum" />
- <java-symbol type="color" name="timepicker_default_selector_color_quantum" />
- <java-symbol type="color" name="timepicker_default_numbers_background_color_quantum" />
- <java-symbol type="style" name="TextAppearance.Quantum.TimePicker.TimeLabel" />
+ <java-symbol type="color" name="timepicker_default_text_color_material" />
+ <java-symbol type="color" name="timepicker_default_disabled_color_material" />
+ <java-symbol type="color" name="timepicker_default_ampm_unselected_background_color_material" />
+ <java-symbol type="color" name="timepicker_default_ampm_selected_background_color_material" />
+ <java-symbol type="color" name="timepicker_default_selector_color_material" />
+ <java-symbol type="color" name="timepicker_default_numbers_background_color_material" />
+ <java-symbol type="style" name="TextAppearance.Material.TimePicker.TimeLabel" />
+ <java-symbol type="attr" name="seekBarPreferenceStyle" />
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index cb5cb0c..5eec197 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -321,6 +321,7 @@
<item name="preferenceInformationStyle">@android:style/Preference.Information</item>
<item name="checkBoxPreferenceStyle">@android:style/Preference.CheckBoxPreference</item>
<item name="switchPreferenceStyle">@android:style/Preference.SwitchPreference</item>
+ <item name="seekBarPreferenceStyle">@android:style/Preference.SeekBarPreference</item>
<item name="yesNoPreferenceStyle">@android:style/Preference.DialogPreference.YesNoPreference</item>
<item name="dialogPreferenceStyle">@android:style/Preference.DialogPreference</item>
<item name="editTextPreferenceStyle">@android:style/Preference.DialogPreference.EditTextPreference</item>
@@ -1203,6 +1204,7 @@
<item name="preferenceInformationStyle">@android:style/Preference.Holo.Information</item>
<item name="checkBoxPreferenceStyle">@android:style/Preference.Holo.CheckBoxPreference</item>
<item name="switchPreferenceStyle">@android:style/Preference.Holo.SwitchPreference</item>
+ <item name="seekBarPreferenceStyle">@android:style/Preference.Holo.SeekBarPreference</item>
<item name="yesNoPreferenceStyle">@android:style/Preference.Holo.DialogPreference.YesNoPreference</item>
<item name="dialogPreferenceStyle">@android:style/Preference.Holo.DialogPreference</item>
<item name="editTextPreferenceStyle">@android:style/Preference.Holo.DialogPreference.EditTextPreference</item>
@@ -1543,6 +1545,7 @@
<item name="preferenceInformationStyle">@android:style/Preference.Holo.Information</item>
<item name="checkBoxPreferenceStyle">@android:style/Preference.Holo.CheckBoxPreference</item>
<item name="switchPreferenceStyle">@android:style/Preference.Holo.SwitchPreference</item>
+ <item name="seekBarPreferenceStyle">@android:style/Preference.Holo.SeekBarPreference</item>
<item name="yesNoPreferenceStyle">@android:style/Preference.Holo.DialogPreference.YesNoPreference</item>
<item name="dialogPreferenceStyle">@android:style/Preference.Holo.DialogPreference</item>
<item name="editTextPreferenceStyle">@android:style/Preference.Holo.DialogPreference.EditTextPreference</item>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index aee35ef..8e83e48 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -38,18 +38,18 @@
to a device’s native theme with all device customizations intact.</p>
<p>For example, when you set your app's {@code targetSdkVersion} to XX or higher, this
theme is applied to your application by default. As such, your app might appear with the
- {@link #Theme_Quantum Quantum} styles on one device, but with a different set of styles on
+ {@link #Theme_Material Material} styles on one device, but with a different set of styles on
another device. This is great if you want your app to fit with the device's native look and
feel. If, however, you prefer to keep your UI style the same across all devices, you should
- apply a specific theme such as {@link #Theme_Quantum Quantum} or one of your own design.
+ apply a specific theme such as {@link #Theme_Material Material} or one of your own design.
For more information, read <a
- href="http://android-developers.blogspot.com/20XX/XX/quantum-everywhere.html">Quantum
+ href="http://android-developers.blogspot.com/20XX/XX/material-everywhere.html">Material
Everywhere</a>.</p>
<p>Styles used by the DeviceDefault theme are named using the convention
Type.DeviceDefault.Etc (for example, {@code Widget.DeviceDefault.Button} and
{@code TextAppearance.DeviceDefault.Widget.PopupMenu.Large}).</p>
-->
- <style name="Theme.DeviceDefault" parent="Theme.Quantum" >
+ <style name="Theme.DeviceDefault" parent="Theme.Material" >
<!-- Text styles -->
<item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
<item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
@@ -160,6 +160,7 @@
<item name="preferenceInformationStyle">@style/Preference.DeviceDefault.Information</item>
<item name="checkBoxPreferenceStyle">@style/Preference.DeviceDefault.CheckBoxPreference</item>
<item name="switchPreferenceStyle">@style/Preference.DeviceDefault.SwitchPreference</item>
+ <item name="seekBarPreferenceStyle">@style/Preference.DeviceDefault.SeekBarPreference</item>
<item name="yesNoPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
<item name="dialogPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference</item>
<item name="editTextPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
@@ -210,27 +211,27 @@
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
- <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Quantum.NoActionBar" />
+ <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Material.NoActionBar" />
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme
sets {@link android.R.attr#windowFullscreen} to true. -->
- <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Quantum.NoActionBar.Fullscreen" />
+ <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Material.NoActionBar.Fullscreen" />
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
extending in to overscan region. This theme
sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
to true. -->
- <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Quantum.NoActionBar.Overscan" />
+ <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Material.NoActionBar.Overscan" />
<!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
{@link android.R.attr#windowTranslucentNavigation} to true. -->
- <style name="Theme.DeviceDefault.NoActionBar.TranslucentDecor" parent="Theme.Quantum.NoActionBar.TranslucentDecor" />
+ <style name="Theme.DeviceDefault.NoActionBar.TranslucentDecor" parent="Theme.Material.NoActionBar.TranslucentDecor" />
<!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
floating (not fill the entire screen), and puts a frame around its contents. You can set this
theme on an activity if you would like to make an activity that looks like a Dialog. -->
- <style name="Theme.DeviceDefault.Dialog" parent="Theme.Quantum.Dialog" >
+ <style name="Theme.DeviceDefault.Dialog" parent="Theme.Material.Dialog" >
<item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
<item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
@@ -243,14 +244,14 @@
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
regular dialog. -->
- <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Quantum.Dialog.MinWidth" />
+ <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth" />
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
- <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Quantum.Dialog.NoActionBar" />
+ <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar" />
<!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
for a regular dialog. -->
- <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Quantum.Dialog.NoActionBar.MinWidth" />
+ <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth" />
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
<style name="Theme.DeviceDefault.Dialog.FixedSize">
@@ -270,49 +271,49 @@
<!-- DeviceDefault theme for a window that will be displayed either full-screen on smaller
screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
- <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Quantum.DialogWhenLarge" />
+ <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Material.DialogWhenLarge" />
<!-- DeviceDefault theme for a window without an action bar that will be displayed either
full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
xlarge). -->
- <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Quantum.DialogWhenLarge.NoActionBar" />
+ <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Material.DialogWhenLarge.NoActionBar" />
<!-- DeviceDefault theme for a presentation window on a secondary display. -->
- <style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Quantum.Dialog.Presentation" />
+ <style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation" />
- <style name="Theme.DeviceDefault.Dialog.TimePicker" parent="Theme.Quantum.Dialog.TimePicker"/>
+ <style name="Theme.DeviceDefault.Dialog.TimePicker" parent="Theme.Material.Dialog.TimePicker"/>
<!-- DeviceDefault theme for panel windows. This removes all extraneous window
decorations, so you basically have an empty rectangle in which to place your content. It makes
the window floating, with a transparent background, and turns off dimming behind the window. -->
- <style name="Theme.DeviceDefault.Panel" parent="Theme.Quantum.Panel" />
+ <style name="Theme.DeviceDefault.Panel" parent="Theme.Material.Panel" />
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
behind them. -->
- <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Quantum.Wallpaper" />
+ <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Material.Wallpaper" />
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
behind them and without an action bar. -->
- <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Quantum.Wallpaper.NoTitleBar" />
+ <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Material.Wallpaper.NoTitleBar" />
<!-- DeviceDefault style for input methods, which is used by the
{@link android.inputmethodservice.InputMethodService} class.-->
- <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Quantum.InputMethod" />
+ <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Material.InputMethod" />
<!-- DeviceDefault style for input methods, which is used by the
{@link android.service.voice.VoiceInteractionSession} class.-->
- <style name="Theme.DeviceDefault.VoiceInteractionSession" parent="Theme.Quantum.VoiceInteractionSession" >
+ <style name="Theme.DeviceDefault.VoiceInteractionSession" parent="Theme.Material.VoiceInteractionSession" >
</style>
- <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Quantum.Dialog.Alert">
+ <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
<item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
</style>
- <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Quantum.SearchBar" />
- <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Quantum.Dialog.NoFrame" />
+ <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Material.SearchBar" />
+ <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame" />
<!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
- <style name="Theme.DeviceDefault.Light" parent="Theme.Quantum.Light" >
+ <style name="Theme.DeviceDefault.Light" parent="Theme.Material.Light" >
<!-- Text styles -->
<item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
<item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
@@ -421,6 +422,7 @@
<item name="preferenceInformationStyle">@style/Preference.DeviceDefault.Information</item>
<item name="checkBoxPreferenceStyle">@style/Preference.DeviceDefault.CheckBoxPreference</item>
<item name="switchPreferenceStyle">@style/Preference.DeviceDefault.SwitchPreference</item>
+ <item name="seekBarPreferenceStyle">@style/Preference.DeviceDefault.SeekBarPreference</item>
<item name="yesNoPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
<item name="dialogPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference</item>
<item name="editTextPreferenceStyle">@style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
@@ -469,30 +471,30 @@
<!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
inverse color profile. -->
- <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Quantum.Light.DarkActionBar" />
+ <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Material.Light.DarkActionBar" />
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
- <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Quantum.Light.NoActionBar" />
+ <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Material.Light.NoActionBar" />
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
This theme sets {@link android.R.attr#windowFullscreen} to true. -->
- <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Quantum.Light.NoActionBar.Fullscreen" />
+ <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Material.Light.NoActionBar.Fullscreen" />
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
and extending in to overscan region. This theme
sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
to true. -->
- <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan" parent="Theme.Quantum.Light.NoActionBar.Overscan" />
+ <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan" parent="Theme.Material.Light.NoActionBar.Overscan" />
<!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
{@link android.R.attr#windowTranslucentNavigation} to true. -->
- <style name="Theme.DeviceDefault.Light.NoActionBar.TranslucentDecor" parent="Theme.Quantum.Light.NoActionBar.TranslucentDecor" />
+ <style name="Theme.DeviceDefault.Light.NoActionBar.TranslucentDecor" parent="Theme.Material.Light.NoActionBar.TranslucentDecor" />
<!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
floating (not fill the entire screen), and puts a frame around its contents. You can set this
theme on an activity if you would like to make an activity that looks like a Dialog.-->
- <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Quantum.Light.Dialog" >
+ <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Material.Light.Dialog" >
<item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
<item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
@@ -505,14 +507,14 @@
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
regular dialog. -->
- <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Quantum.Light.Dialog.MinWidth" />
+ <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Material.Light.Dialog.MinWidth" />
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
- <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Quantum.Light.Dialog.NoActionBar" />
+ <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Material.Light.Dialog.NoActionBar" />
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
width for a regular dialog. -->
- <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Quantum.Light.Dialog.NoActionBar.MinWidth" />
+ <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Light.Dialog.NoActionBar.MinWidth" />
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
<style name="Theme.DeviceDefault.Light.Dialog.FixedSize">
@@ -532,27 +534,30 @@
<!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller
screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
- <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Quantum.Light.DialogWhenLarge" />
+ <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge" />
<!-- DeviceDefault light theme for a window without an action bar that will be displayed either
full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
xlarge). -->
- <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Quantum.Light.DialogWhenLarge.NoActionBar" />
+ <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar" />
<!-- DeviceDefault light theme for a presentation window on a secondary display. -->
- <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Quantum.Light.Dialog.Presentation" />
+ <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation" />
- <style name="Theme.DeviceDefault.Light.Dialog.TimePicker" parent="Theme.Quantum.Light.Dialog.TimePicker"/>
+ <style name="Theme.DeviceDefault.Light.Dialog.TimePicker" parent="Theme.Material.Light.Dialog.TimePicker"/>
<!-- DeviceDefault light theme for panel windows. This removes all extraneous window
decorations, so you basically have an empty rectangle in which to place your content. It makes
the window floating, with a transparent background, and turns off dimming behind the window. -->
- <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Quantum.Light.Panel" />
+ <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Material.Light.Panel" />
- <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Quantum.Light.Dialog.Alert">
+ <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
<item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
</style>
- <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Quantum.Light.SearchBar" />
+ <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar" />
+
+ <!-- DeviceDefault theme for a window that should look like the Settings app. -->
+ <style name="Theme.DeviceDefault.Settings" parent="Theme.Material.Settings" />
</resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
new file mode 100644
index 0000000..77e4307
--- /dev/null
+++ b/core/res/res/values/themes_material.xml
@@ -0,0 +1,1252 @@
+<?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.
+-->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see themes_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+<resources>
+
+ <!-- Material theme (dark version).
+ <p>If you want to ensure that your
+ app consistently uses the Material theme at all times, you must explicitly declare it in your
+ manifest. For example, {@code <application android:theme="@style/Theme.Material">}.
+
+ <p>Styles used by the Material theme are named using the convention Type.Material.Etc
+ (for example, {@code Widget.Material.Button} and {@code
+ TextAppearance.Material.Widget.PopupMenu.Large}).
+ Specific resources used by Material are named using the convention @type/foo_bar_baz_material
+ with trailing _dark or _light specifiers if they are not shared between both light and
+ dark versions of the theme. -->
+ <style name="Theme.Material">
+ <item name="colorForeground">@color/bright_foreground_material_dark</item>
+ <item name="colorForegroundInverse">@color/bright_foreground_material_light</item>
+ <item name="colorBackground">@color/background_material_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
+ <item name="disabledAlpha">0.5</item>
+ <item name="backgroundDimAmount">0.6</item>
+
+ <!-- Text styles -->
+ <item name="textAppearance">@style/TextAppearance.Material</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
+
+ <item name="textColorPrimary">@color/primary_text_material_dark</item>
+ <item name="textColorPrimaryInverse">@color/primary_text_material_light</item>
+ <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_dark</item>
+ <item name="textColorSecondary">@color/secondary_text_material_dark</item>
+ <item name="textColorSecondaryInverse">@color/secondary_text_material_light</item>
+ <item name="textColorTertiary">@color/tertiary_text_material_dark</item>
+ <item name="textColorTertiaryInverse">@color/tertiary_text_material_light</item>
+ <item name="textColorHint">@color/hint_foreground_material_dark</item>
+ <item name="textColorHintInverse">@color/hint_foreground_material_light</item>
+ <item name="textColorHighlight">@color/highlighted_text_material_dark</item>
+ <item name="textColorHighlightInverse">@color/highlighted_text_material_light</item>
+ <item name="textColorLink">@color/material_teal_500</item>
+ <item name="textColorLinkInverse">@color/material_teal_500</item>
+ <item name="textColorSearchUrl">@color/search_url_text_material_dark</item>
+ <item name="textColorAlertDialogListItem">@color/primary_text_material_dark</item>
+
+ <item name="textAppearanceLarge">@style/TextAppearance.Material.Large</item>
+ <item name="textAppearanceLargeInverse">@style/TextAppearance.Material.Large.Inverse</item>
+ <item name="textAppearanceMedium">@style/TextAppearance.Material.Medium</item>
+ <item name="textAppearanceMediumInverse">@style/TextAppearance.Material.Medium.Inverse</item>
+ <item name="textAppearanceSmall">@style/TextAppearance.Material.Small</item>
+ <item name="textAppearanceSmallInverse">@style/TextAppearance.Material.Small.Inverse</item>
+ <item name="textAppearanceSearchResultTitle">@style/TextAppearance.Material.SearchResult.Title</item>
+ <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.Material.SearchResult.Subtitle</item>
+
+ <item name="textAppearanceButton">@style/TextAppearance.Material.Widget.Button</item>
+
+ <item name="editTextColor">?attr/textColorPrimary</item>
+ <item name="editTextBackground">@drawable/edit_text_material</item>
+
+ <item name="candidatesTextStyleSpans">@string/candidates_style</item>
+
+ <item name="textCheckMark">@drawable/indicator_check_mark_dark</item>
+ <item name="textCheckMarkInverse">@drawable/indicator_check_mark_light</item>
+
+ <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Large</item>
+ <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Small</item>
+
+ <!-- Button styles -->
+ <item name="buttonStyle">@style/Widget.Material.Button</item>
+ <item name="buttonStyleSmall">@style/Widget.Material.Button.Small</item>
+ <item name="buttonStyleInset">@style/Widget.Material.Button.Inset</item>
+ <item name="buttonStyleToggle">@style/Widget.Material.Button.Toggle</item>
+
+ <item name="switchStyle">@style/Widget.Material.CompoundButton.Switch</item>
+ <item name="mediaRouteButtonStyle">@style/Widget.Material.MediaRouteButton</item>
+
+ <item name="selectableItemBackground">@drawable/item_background_material</item>
+ <item name="selectableItemBackgroundBorderless">@drawable/item_background_borderless_material</item>
+ <item name="borderlessButtonStyle">@style/Widget.Material.Button.Borderless</item>
+ <item name="homeAsUpIndicator">@drawable/ic_ab_back_material</item>
+
+ <!-- List attributes -->
+ <item name="listPreferredItemHeight">64dip</item>
+ <item name="listPreferredItemHeightSmall">48dip</item>
+ <item name="listPreferredItemHeightLarge">80dip</item>
+ <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
+ <item name="textAppearanceListItem">@style/TextAppearance.Material.Subhead</item>
+ <item name="textAppearanceListItemSmall">@style/TextAppearance.Material.Subhead</item>
+ <item name="textAppearanceListItemSecondary">@style/TextAppearance.Material.Body1</item>
+ <item name="listPreferredItemPaddingLeft">16dip</item>
+ <item name="listPreferredItemPaddingRight">16dip</item>
+ <item name="listPreferredItemPaddingStart">16dip</item>
+ <item name="listPreferredItemPaddingEnd">16dip</item>
+
+ <!-- @hide -->
+ <item name="searchResultListItemHeight">58dip</item>
+ <item name="listDivider">@drawable/list_divider_material</item>
+ <item name="listSeparatorTextViewStyle">@style/Widget.Material.TextView.ListSeparator</item>
+
+ <item name="listChoiceIndicatorSingle">@drawable/btn_radio_material_anim</item>
+ <item name="listChoiceIndicatorMultiple">@drawable/btn_check_material_anim</item>
+
+ <item name="listChoiceBackgroundIndicator">?attr/selectableItemBackground</item>
+ <item name="activatedBackgroundIndicator">@drawable/activated_background_material</item>
+
+ <item name="listDividerAlertDialog">@drawable/list_divider_material</item>
+
+ <item name="expandableListPreferredItemPaddingLeft">40dip</item>
+ <item name="expandableListPreferredChildPaddingLeft">?attr/expandableListPreferredItemPaddingLeft</item>
+
+ <item name="expandableListPreferredItemIndicatorLeft">3dip</item>
+ <item name="expandableListPreferredItemIndicatorRight">0dip</item>
+ <item name="expandableListPreferredChildIndicatorLeft">?attr/expandableListPreferredItemIndicatorLeft</item>
+ <item name="expandableListPreferredChildIndicatorRight">?attr/expandableListPreferredItemIndicatorRight</item>
+ <item name="findOnPageNextDrawable">@drawable/ic_find_next_material</item>
+ <item name="findOnPagePreviousDrawable">@drawable/ic_find_previous_material</item>
+
+ <!-- Gallery attributes -->
+ <item name="galleryItemBackground">@drawable/gallery_item_background</item>
+
+ <!-- Window attributes -->
+ <item name="windowBackground">@color/background_material_dark</item>
+ <item name="windowFrame">@null</item>
+ <item name="windowNoTitle">false</item>
+ <item name="windowFullscreen">false</item>
+ <item name="windowOverscan">false</item>
+ <item name="windowIsFloating">false</item>
+ <item name="windowContentOverlay">@null</item>
+ <item name="windowShowWallpaper">false</item>
+ <item name="windowTitleStyle">@style/WindowTitle.Material</item>
+ <item name="windowTitleSize">@dimen/action_bar_default_height_material</item>
+ <item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.Material</item>
+ <item name="windowContentTransitions">false</item>
+ <item name="windowAnimationStyle">@style/Animation.Material.Activity</item>
+ <item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
+ <item name="windowActionBar">true</item>
+ <item name="windowActionModeOverlay">false</item>
+ <item name="windowDrawsSystemBarBackgrounds">true</item>
+ <item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
+ <item name="statusBarColor">?attr/colorPrimaryDark</item>
+ <item name="navigationBarColor">@color/black</item>
+ <item name="windowEnterTransition">@transition/fade</item>
+ <item name="windowSharedElementEnterTransition">@transition/move</item>
+ <item name="windowSharedElementExitTransition">@transition/move</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogTheme">@style/Theme.Material.Dialog</item>
+ <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_material</item>
+ <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
+ <item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
+
+ <!-- AlertDialog attributes -->
+ <item name="alertDialogTheme">@style/Theme.Material.Dialog.Alert</item>
+ <item name="alertDialogStyle">@style/AlertDialog.Material</item>
+ <item name="alertDialogCenterButtons">false</item>
+ <item name="alertDialogIcon">@drawable/ic_dialog_alert_material</item>
+
+ <!-- Presentation attributes -->
+ <item name="presentationTheme">@style/Theme.Material.Dialog.Presentation</item>
+
+ <!-- Toast attributes -->
+ <item name="toastFrameBackground">@drawable/toast_frame</item>
+
+ <!-- Panel attributes -->
+ <item name="panelBackground">?attr/colorBackground</item>
+ <item name="panelFullBackground">@drawable/menu_background_fill_parent_width</item>
+ <!-- These three attributes do not seems to be used by the framework. Declared public though -->
+ <item name="panelColorBackground">#000</item>
+ <item name="panelColorForeground">?attr/textColorPrimary</item>
+ <item name="panelTextAppearance">?attr/textAppearance</item>
+
+ <item name="panelMenuIsCompact">true</item>
+ <item name="panelMenuListWidth">250dip</item>
+ <item name="panelMenuListTheme">@style/Theme.Material.CompactMenu</item>
+
+ <!-- Scrollbar attributes -->
+ <item name="scrollbarFadeDuration">250</item>
+ <item name="scrollbarDefaultDelayBeforeFade">300</item>
+ <item name="scrollbarSize">10dip</item>
+ <item name="scrollbarThumbHorizontal">@drawable/scrollbar_handle_material</item>
+ <item name="scrollbarThumbVertical">@drawable/scrollbar_handle_material</item>
+ <item name="scrollbarTrackHorizontal">@null</item>
+ <item name="scrollbarTrackVertical">@null</item>
+
+ <!-- Text selection handle attributes -->
+ <item name="textSelectHandleLeft">@drawable/text_select_handle_left_material</item>
+ <item name="textSelectHandleRight">@drawable/text_select_handle_right_material</item>
+ <item name="textSelectHandle">@drawable/text_select_handle_middle_material</item>
+ <item name="textSelectHandleWindowStyle">@style/Widget.Material.TextSelectHandle</item>
+ <item name="textSuggestionsWindowStyle">@style/Widget.Material.TextSuggestionsPopupWindow</item>
+ <item name="textCursorDrawable">@drawable/text_cursor_material</item>
+
+ <!-- Widget styles -->
+ <item name="absListViewStyle">@style/Widget.Material.AbsListView</item>
+ <item name="autoCompleteTextViewStyle">@style/Widget.Material.AutoCompleteTextView</item>
+ <item name="checkboxStyle">@style/Widget.Material.CompoundButton.CheckBox</item>
+ <item name="checkedTextViewStyle">@style/Widget.Material.CheckedTextView</item>
+ <item name="dropDownListViewStyle">@style/Widget.Material.ListView.DropDown</item>
+ <item name="editTextStyle">@style/Widget.Material.EditText</item>
+ <item name="expandableListViewStyle">@style/Widget.Material.ExpandableListView</item>
+ <item name="expandableListViewWhiteStyle">@style/Widget.Material.ExpandableListView.White</item>
+ <item name="fastScrollStyle">@style/Widget.Material.FastScroll</item>
+ <item name="galleryStyle">@style/Widget.Material.Gallery</item>
+ <item name="gestureOverlayViewStyle">@style/Widget.Material.GestureOverlayView</item>
+ <item name="gridViewStyle">@style/Widget.Material.GridView</item>
+ <item name="imageButtonStyle">@style/Widget.Material.ImageButton</item>
+ <item name="imageWellStyle">@style/Widget.Material.ImageWell</item>
+ <item name="listViewStyle">@style/Widget.Material.ListView</item>
+ <item name="listViewWhiteStyle">@style/Widget.Material.ListView.White</item>
+ <item name="popupWindowStyle">@style/Widget.Material.PopupWindow</item>
+ <item name="progressBarStyle">@style/Widget.Material.ProgressBar</item>
+ <item name="progressBarStyleHorizontal">@style/Widget.Material.ProgressBar.Horizontal</item>
+ <item name="progressBarStyleSmall">@style/Widget.Material.ProgressBar.Small</item>
+ <item name="progressBarStyleSmallTitle">@style/Widget.Material.ProgressBar.Small.Title</item>
+ <item name="progressBarStyleLarge">@style/Widget.Material.ProgressBar.Large</item>
+ <item name="progressBarStyleInverse">@style/Widget.Material.ProgressBar.Inverse</item>
+ <item name="progressBarStyleSmallInverse">@style/Widget.Material.ProgressBar.Small.Inverse</item>
+ <item name="progressBarStyleLargeInverse">@style/Widget.Material.ProgressBar.Large.Inverse</item>
+ <item name="seekBarStyle">@style/Widget.Material.SeekBar</item>
+ <item name="ratingBarStyle">@style/Widget.Material.RatingBar</item>
+ <item name="ratingBarStyleIndicator">@style/Widget.Material.RatingBar.Indicator</item>
+ <item name="ratingBarStyleSmall">@style/Widget.Material.RatingBar.Small</item>
+ <item name="radioButtonStyle">@style/Widget.Material.CompoundButton.RadioButton</item>
+ <item name="scrollViewStyle">@style/Widget.Material.ScrollView</item>
+ <item name="horizontalScrollViewStyle">@style/Widget.Material.HorizontalScrollView</item>
+ <item name="spinnerStyle">?attr/dropDownSpinnerStyle</item>
+ <item name="dropDownSpinnerStyle">@style/Widget.Material.Spinner.DropDown</item>
+ <item name="starStyle">@style/Widget.Material.CompoundButton.Star</item>
+ <item name="tabWidgetStyle">@style/Widget.Material.TabWidget</item>
+ <item name="textViewStyle">@style/Widget.Material.TextView</item>
+ <item name="errorMessageBackground">@drawable/popup_inline_error_holo_dark</item>
+ <item name="errorMessageAboveBackground">@drawable/popup_inline_error_above_holo_dark</item>
+ <item name="webTextViewStyle">@style/Widget.Material.WebTextView</item>
+ <item name="webViewStyle">@style/Widget.Material.WebView</item>
+ <item name="dropDownItemStyle">@style/Widget.Material.DropDownItem</item>
+ <item name="spinnerDropDownItemStyle">@style/Widget.Material.DropDownItem.Spinner</item>
+ <item name="spinnerItemStyle">@style/Widget.Material.TextView.SpinnerItem</item>
+ <item name="dropDownHintAppearance">@style/TextAppearance.Material.Widget.DropDownHint</item>
+ <item name="keyboardViewStyle">@style/Widget.Material.KeyboardView</item>
+ <item name="quickContactBadgeStyleWindowSmall">@style/Widget.Material.QuickContactBadge.WindowSmall</item>
+ <item name="quickContactBadgeStyleWindowMedium">@style/Widget.Material.QuickContactBadge.WindowMedium</item>
+ <item name="quickContactBadgeStyleWindowLarge">@style/Widget.Material.QuickContactBadge.WindowLarge</item>
+ <item name="quickContactBadgeStyleSmallWindowSmall">@style/Widget.Material.QuickContactBadgeSmall.WindowSmall</item>
+ <item name="quickContactBadgeStyleSmallWindowMedium">@style/Widget.Material.QuickContactBadgeSmall.WindowMedium</item>
+ <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Material.QuickContactBadgeSmall.WindowLarge</item>
+ <item name="listPopupWindowStyle">@style/Widget.Material.ListPopupWindow</item>
+ <item name="popupMenuStyle">@style/Widget.Material.PopupMenu</item>
+ <item name="stackViewStyle">@style/Widget.Material.StackView</item>
+ <item name="activityChooserViewStyle">@style/Widget.Material.ActivityChooserView</item>
+
+ <!-- Preference styles -->
+ <item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item>
+ <item name="preferenceFragmentStyle">@style/PreferenceFragment.Material</item>
+ <item name="preferenceCategoryStyle">@style/Preference.Material.Category</item>
+ <item name="preferenceStyle">@style/Preference.Material</item>
+ <item name="preferenceInformationStyle">@style/Preference.Material.Information</item>
+ <item name="checkBoxPreferenceStyle">@style/Preference.Material.CheckBoxPreference</item>
+ <item name="switchPreferenceStyle">@style/Preference.Material.SwitchPreference</item>
+ <item name="seekBarPreferenceStyle">@style/Preference.Material.SeekBarPreference</item>
+ <item name="yesNoPreferenceStyle">@style/Preference.Material.DialogPreference.YesNoPreference</item>
+ <item name="dialogPreferenceStyle">@style/Preference.Material.DialogPreference</item>
+ <item name="editTextPreferenceStyle">@style/Preference.Material.DialogPreference.EditTextPreference</item>
+ <item name="ringtonePreferenceStyle">@style/Preference.Material.RingtonePreference</item>
+ <item name="preferenceLayoutChild">@layout/preference_child_material</item>
+ <item name="preferencePanelStyle">@style/PreferencePanel.Material</item>
+ <item name="preferenceHeaderPanelStyle">@style/PreferenceHeaderPanel.Material</item>
+ <item name="preferenceListStyle">@style/PreferenceHeaderList.Material</item>
+ <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Material</item>
+ <item name="preferenceFragmentPaddingSide">@dimen/preference_fragment_padding_side_material</item>
+ <item name="detailsElementBackground">?attr/colorBackground</item>
+
+ <!-- Search widget styles -->
+ <item name="searchWidgetCorpusItemBackground">@color/search_widget_corpus_item_background</item>
+
+ <!-- Action bar styles -->
+ <item name="actionDropDownStyle">@style/Widget.Material.Spinner.DropDown.ActionBar</item>
+ <item name="actionButtonStyle">@style/Widget.Material.ActionButton</item>
+ <item name="actionOverflowButtonStyle">@style/Widget.Material.ActionButton.Overflow</item>
+ <item name="actionOverflowMenuStyle">@android:style/Widget.Material.PopupMenu.Overflow</item>
+ <item name="actionModeBackground">?attr/colorPrimaryDark</item>
+ <item name="actionModeSplitBackground">?attr/colorPrimaryDark</item>
+ <item name="actionModeCloseDrawable">@drawable/ic_cab_done_material</item>
+ <item name="actionBarTabStyle">@style/Widget.Material.ActionBar.TabView</item>
+ <item name="actionBarTabBarStyle">@style/Widget.Material.ActionBar.TabBar</item>
+ <item name="actionBarTabTextStyle">@style/Widget.Material.ActionBar.TabText</item>
+ <item name="actionModeStyle">@style/Widget.Material.ActionMode</item>
+ <item name="actionModeCloseButtonStyle">@style/Widget.Material.ActionButton.CloseMode</item>
+ <item name="actionBarStyle">@style/Widget.Material.ActionBar.Solid</item>
+ <item name="actionBarSize">@dimen/action_bar_default_height_material</item>
+ <item name="actionModePopupWindowStyle">@style/Widget.Material.PopupWindow.ActionMode</item>
+ <item name="actionBarWidgetTheme">@null</item>
+ <item name="actionBarTheme">@style/ThemeOverlay.Material.ActionBar</item>
+ <item name="actionBarItemBackground">?attr/selectableItemBackgroundBorderless</item>
+
+ <item name="actionModeCutDrawable">@drawable/ic_menu_cut_material</item>
+ <item name="actionModeCopyDrawable">@drawable/ic_menu_copy_material</item>
+ <item name="actionModePasteDrawable">@drawable/ic_menu_paste_material</item>
+ <item name="actionModeSelectAllDrawable">@drawable/ic_menu_selectall_material</item>
+ <item name="actionModeShareDrawable">@drawable/ic_menu_share_material</item>
+ <item name="actionModeFindDrawable">@drawable/ic_menu_find_material</item>
+ <item name="actionModeWebSearchDrawable">@drawable/ic_menu_search_material</item>
+
+ <item name="toolbarStyle">@style/Widget.Material.Toolbar</item>
+
+ <item name="dividerVertical">?attr/listDivider</item>
+ <item name="dividerHorizontal">?attr/listDivider</item>
+ <item name="buttonBarStyle">@style/Widget.Material.ButtonBar</item>
+ <item name="buttonBarButtonStyle">@style/Widget.Material.Button.Borderless</item>
+ <item name="segmentedButtonStyle">@style/Widget.Material.SegmentedButton</item>
+
+ <!-- SearchView attributes -->
+ <item name="searchDropdownBackground">?attr/colorBackground</item>
+ <item name="searchViewTextField">@drawable/textfield_search_material</item>
+ <item name="searchViewTextFieldRight">@drawable/textfield_search_material</item>
+ <item name="searchViewCloseIcon">@android:drawable/ic_clear_material</item>
+ <item name="searchViewSearchIcon">@android:drawable/ic_search_api_material</item>
+ <item name="searchViewGoIcon">@android:drawable/ic_go_search_api_material</item>
+ <item name="searchViewVoiceIcon">@android:drawable/ic_voice_search_api_material</item>
+ <item name="searchViewEditQuery">@android:drawable/ic_commit_search_api_material</item>
+
+ <item name="searchDialogTheme">@style/Theme.Material.SearchBar</item>
+
+ <!-- PreferenceFrameLayout attributes -->
+ <item name="preferenceFrameLayoutStyle">@style/Widget.Material.PreferenceFrameLayout</item>
+
+ <!-- NumberPicker style-->
+ <item name="numberPickerStyle">@style/Widget.Material.NumberPicker</item>
+
+ <!-- CalendarView style-->
+ <item name="calendarViewStyle">@style/Widget.Material.CalendarView</item>
+
+ <!-- TimePicker style -->
+ <item name="timePickerStyle">@style/Widget.Material.TimePicker</item>
+
+ <!-- TimePicker background color -->
+ <item name="timePickerHeaderBackgroundColor">?colorBackground</item>
+
+ <!-- TimePicker Header time label text appearance -->
+ <item name="timePickerHeaderTimeLabelTextAppearance">@style/TextAppearance.Material.TimePicker.TimeLabel</item>
+
+ <!-- TimePicker Header am pm label text appearance -->
+ <item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.Material.TimePicker.AmPmLabel</item>
+
+ <!-- TimePicker dialog theme -->
+ <item name="timePickerDialogTheme">@style/Theme.Material.Dialog.TimePicker</item>
+
+ <!-- DatePicker style -->
+ <item name="datePickerStyle">@style/Widget.Material.DatePicker</item>
+
+ <!-- TODO: This belongs in a FastScroll style -->
+ <item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_material</item>
+ <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_dark</item>
+ <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_dark</item>
+ <item name="fastScrollTrackDrawable">@drawable/fastscroll_track_material</item>
+ <item name="fastScrollOverlayPosition">atThumb</item>
+
+ <!-- Color palette -->
+ <item name="colorPrimaryDark">@color/material_blue_grey_900</item>
+ <item name="colorPrimary">@color/material_blue_grey_800</item>
+ <item name="colorAccent">@color/material_light_blue_A200</item>
+
+ <item name="colorControlNormal">?attr/textColorSecondary</item>
+ <item name="colorControlActivated">?attr/colorAccent</item>
+
+ <item name="colorControlHighlight">@color/ripple_material_dark</item>
+ <item name="colorButtonNormal">@color/btn_default_material_dark</item>
+ </style>
+
+ <!-- Material theme (light version). -->
+ <style name="Theme.Material.Light" parent="Theme.Light">
+ <item name="colorForeground">@color/bright_foreground_material_light</item>
+ <item name="colorForegroundInverse">@color/bright_foreground_material_dark</item>
+ <item name="colorBackground">@color/background_material_light</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
+ <item name="disabledAlpha">0.5</item>
+ <item name="backgroundDimAmount">0.6</item>
+
+ <!-- Text styles -->
+ <item name="textAppearance">@style/TextAppearance.Material</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
+
+ <item name="textColorPrimary">@color/primary_text_material_light</item>
+ <item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
+ <item name="textColorSecondary">@color/secondary_text_material_light</item>
+ <item name="textColorSecondaryInverse">@color/secondary_text_material_dark</item>
+ <item name="textColorTertiary">@color/tertiary_text_material_light</item>
+ <item name="textColorTertiaryInverse">@color/tertiary_text_material_dark</item>
+ <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_light</item>
+ <item name="textColorPrimaryInverseDisableOnly">@color/primary_text_disable_only_material_dark</item>
+ <item name="textColorHint">@color/hint_foreground_material_light</item>
+ <item name="textColorHintInverse">@color/hint_foreground_material_dark</item>
+ <item name="textColorHighlight">@color/highlighted_text_material_light</item>
+ <item name="textColorHighlightInverse">@color/highlighted_text_material_dark</item>
+ <item name="textColorLink">@color/material_teal_500</item>
+ <item name="textColorLinkInverse">@color/material_teal_500</item>
+ <item name="textColorSearchUrl">@color/search_url_text_material_light</item>
+ <item name="textColorAlertDialogListItem">@color/primary_text_material_light</item>
+
+ <item name="textAppearanceLarge">@style/TextAppearance.Material.Large</item>
+ <item name="textAppearanceLargeInverse">@style/TextAppearance.Material.Large.Inverse</item>
+ <item name="textAppearanceMedium">@style/TextAppearance.Material.Medium</item>
+ <item name="textAppearanceMediumInverse">@style/TextAppearance.Material.Medium.Inverse</item>
+ <item name="textAppearanceSmall">@style/TextAppearance.Material.Small</item>
+ <item name="textAppearanceSmallInverse">@style/TextAppearance.Material.Small.Inverse</item>
+ <item name="textAppearanceSearchResultTitle">@style/TextAppearance.Material.SearchResult.Title</item>
+ <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.Material.SearchResult.Subtitle</item>
+
+ <item name="textAppearanceButton">@style/TextAppearance.Material.Widget.Button</item>
+
+ <item name="editTextColor">?attr/textColorPrimary</item>
+ <item name="editTextBackground">@drawable/edit_text_material</item>
+
+ <item name="candidatesTextStyleSpans">@string/candidates_style</item>
+
+ <item name="textCheckMark">@drawable/indicator_check_mark_light</item>
+ <item name="textCheckMarkInverse">@drawable/indicator_check_mark_dark</item>
+
+ <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Large</item>
+ <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Small</item>
+
+ <!-- Button styles -->
+ <item name="buttonStyle">@style/Widget.Material.Light.Button</item>
+
+ <item name="buttonStyleSmall">@style/Widget.Material.Light.Button.Small</item>
+ <item name="buttonStyleInset">@style/Widget.Material.Light.Button.Inset</item>
+
+ <item name="buttonStyleToggle">@style/Widget.Material.Light.Button.Toggle</item>
+ <item name="switchStyle">@style/Widget.Material.Light.CompoundButton.Switch</item>
+ <item name="mediaRouteButtonStyle">@style/Widget.Material.Light.MediaRouteButton</item>
+
+ <item name="selectableItemBackground">@drawable/item_background_material</item>
+ <item name="selectableItemBackgroundBorderless">@drawable/item_background_borderless_material</item>
+ <item name="borderlessButtonStyle">@style/Widget.Material.Light.Button.Borderless</item>
+ <item name="homeAsUpIndicator">@drawable/ic_ab_back_material</item>
+
+ <!-- List attributes -->
+ <item name="listPreferredItemHeight">64dip</item>
+ <item name="listPreferredItemHeightSmall">48dip</item>
+ <item name="listPreferredItemHeightLarge">80dip</item>
+ <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
+ <item name="textAppearanceListItem">@style/TextAppearance.Material.Subhead</item>
+ <item name="textAppearanceListItemSmall">@style/TextAppearance.Material.Subhead</item>
+ <item name="textAppearanceListItemSecondary">@style/TextAppearance.Material.Body1</item>
+ <item name="listPreferredItemPaddingLeft">16dip</item>
+ <item name="listPreferredItemPaddingRight">16dip</item>
+ <item name="listPreferredItemPaddingStart">16dip</item>
+ <item name="listPreferredItemPaddingEnd">16dip</item>
+
+ <!-- @hide -->
+ <item name="searchResultListItemHeight">58dip</item>
+ <item name="listDivider">@drawable/list_divider_material</item>
+ <item name="listSeparatorTextViewStyle">@style/Widget.Material.Light.TextView.ListSeparator</item>
+
+ <item name="listChoiceIndicatorSingle">@drawable/btn_radio_material_anim</item>
+ <item name="listChoiceIndicatorMultiple">@drawable/btn_check_material_anim</item>
+
+ <item name="listChoiceBackgroundIndicator">?attr/selectableItemBackground</item>
+ <item name="activatedBackgroundIndicator">@drawable/activated_background_material</item>
+
+ <item name="expandableListPreferredItemPaddingLeft">40dip</item>
+ <item name="expandableListPreferredChildPaddingLeft">?attr/expandableListPreferredItemPaddingLeft</item>
+
+ <item name="expandableListPreferredItemIndicatorLeft">3dip</item>
+ <item name="expandableListPreferredItemIndicatorRight">0dip</item>
+ <item name="expandableListPreferredChildIndicatorLeft">?attr/expandableListPreferredItemIndicatorLeft</item>
+ <item name="expandableListPreferredChildIndicatorRight">?attr/expandableListPreferredItemIndicatorRight</item>
+
+ <item name="listDividerAlertDialog">@drawable/list_divider_material</item>
+ <item name="findOnPageNextDrawable">@drawable/ic_find_next_material</item>
+ <item name="findOnPagePreviousDrawable">@drawable/ic_find_previous_material</item>
+
+ <!-- Gallery attributes -->
+ <item name="galleryItemBackground">@drawable/gallery_item_background</item>
+
+ <!-- Window attributes -->
+ <item name="windowBackground">@color/background_material_light</item>
+ <item name="windowFrame">@null</item>
+ <item name="windowNoTitle">false</item>
+ <item name="windowFullscreen">false</item>
+ <item name="windowOverscan">false</item>
+ <item name="windowIsFloating">false</item>
+ <item name="windowContentOverlay">@drawable/ab_solid_shadow_material</item>
+ <item name="windowShowWallpaper">false</item>
+ <item name="windowTitleStyle">@style/WindowTitle.Material</item>
+ <item name="windowTitleSize">@dimen/action_bar_default_height_material</item>
+ <item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.Material</item>
+ <item name="windowAnimationStyle">@style/Animation.Material.Activity</item>
+ <item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
+ <item name="windowActionBar">true</item>
+ <item name="windowActionModeOverlay">false</item>
+ <item name="windowDrawsSystemBarBackgrounds">true</item>
+ <item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
+ <item name="statusBarColor">?attr/colorPrimaryDark</item>
+ <item name="navigationBarColor">@color/black</item>
+ <item name="windowEnterTransition">@transition/fade</item>
+ <item name="windowSharedElementEnterTransition">@transition/move</item>
+ <item name="windowSharedElementExitTransition">@transition/move</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogTheme">@style/Theme.Material.Light.Dialog</item>
+ <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_material</item>
+ <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
+ <item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
+
+ <!-- AlertDialog attributes -->
+ <item name="alertDialogTheme">@style/Theme.Material.Light.Dialog.Alert</item>
+ <item name="alertDialogStyle">@style/AlertDialog.Material.Light</item>
+ <item name="alertDialogCenterButtons">false</item>
+ <item name="alertDialogIcon">@drawable/ic_dialog_alert_material</item>
+
+ <!-- Presentation attributes -->
+ <item name="presentationTheme">@style/Theme.Material.Light.Dialog.Presentation</item>
+
+ <!-- Toast attributes -->
+ <item name="toastFrameBackground">@drawable/toast_frame</item>
+
+ <!-- Panel attributes -->
+ <item name="panelBackground">?attr/colorBackground</item>
+ <item name="panelFullBackground">@drawable/menu_background_fill_parent_width</item>
+ <!-- These three attributes do not seems to be used by the framework. Declared public though -->
+ <item name="panelColorBackground">#000</item>
+ <item name="panelColorForeground">?attr/textColorPrimary</item>
+ <item name="panelTextAppearance">?attr/textAppearance</item>
+
+ <item name="panelMenuIsCompact">true</item>
+ <item name="panelMenuListWidth">250dip</item>
+ <item name="panelMenuListTheme">@style/Theme.Material.Light.CompactMenu</item>
+
+ <!-- Scrollbar attributes -->
+ <item name="scrollbarFadeDuration">250</item>
+ <item name="scrollbarDefaultDelayBeforeFade">300</item>
+ <item name="scrollbarSize">10dip</item>
+ <item name="scrollbarThumbHorizontal">@drawable/scrollbar_handle_material</item>
+ <item name="scrollbarThumbVertical">@drawable/scrollbar_handle_material</item>
+ <item name="scrollbarTrackHorizontal">@null</item>
+ <item name="scrollbarTrackVertical">@null</item>
+
+ <!-- Text selection handle attributes -->
+ <item name="textSelectHandleLeft">@drawable/text_select_handle_left_material</item>
+ <item name="textSelectHandleRight">@drawable/text_select_handle_right_material</item>
+ <item name="textSelectHandle">@drawable/text_select_handle_middle_material</item>
+ <item name="textSelectHandleWindowStyle">@style/Widget.Material.TextSelectHandle</item>
+ <item name="textSuggestionsWindowStyle">@style/Widget.Material.Light.TextSuggestionsPopupWindow</item>
+ <item name="textCursorDrawable">@drawable/text_cursor_material</item>
+
+ <!-- Widget styles -->
+ <item name="absListViewStyle">@style/Widget.Material.Light.AbsListView</item>
+ <item name="autoCompleteTextViewStyle">@style/Widget.Material.Light.AutoCompleteTextView</item>
+ <item name="checkboxStyle">@style/Widget.Material.Light.CompoundButton.CheckBox</item>
+ <item name="checkedTextViewStyle">@style/Widget.Material.Light.CheckedTextView</item>
+ <item name="dropDownListViewStyle">@style/Widget.Material.ListView.DropDown</item>
+ <item name="editTextStyle">@style/Widget.Material.Light.EditText</item>
+ <item name="expandableListViewStyle">@style/Widget.Material.Light.ExpandableListView</item>
+ <item name="expandableListViewWhiteStyle">@style/Widget.Material.Light.ExpandableListView.White</item>
+ <item name="fastScrollStyle">@style/Widget.Material.Light.FastScroll</item>
+ <item name="galleryStyle">@style/Widget.Material.Light.Gallery</item>
+ <item name="gestureOverlayViewStyle">@style/Widget.Material.Light.GestureOverlayView</item>
+ <item name="gridViewStyle">@style/Widget.Material.Light.GridView</item>
+ <item name="imageButtonStyle">@style/Widget.Material.Light.ImageButton</item>
+ <item name="imageWellStyle">@style/Widget.Material.Light.ImageWell</item>
+ <item name="listViewStyle">@style/Widget.Material.Light.ListView</item>
+ <item name="listViewWhiteStyle">@style/Widget.Material.Light.ListView.White</item>
+ <item name="popupWindowStyle">@style/Widget.Material.Light.PopupWindow</item>
+ <item name="progressBarStyle">@style/Widget.Material.Light.ProgressBar</item>
+ <item name="progressBarStyleHorizontal">@style/Widget.Material.Light.ProgressBar.Horizontal</item>
+ <item name="progressBarStyleSmall">@style/Widget.Material.Light.ProgressBar.Small</item>
+ <item name="progressBarStyleSmallTitle">@style/Widget.Material.Light.ProgressBar.Small.Title</item>
+ <item name="progressBarStyleLarge">@style/Widget.Material.Light.ProgressBar.Large</item>
+ <item name="progressBarStyleInverse">@style/Widget.Material.Light.ProgressBar.Inverse</item>
+ <item name="progressBarStyleSmallInverse">@style/Widget.Material.Light.ProgressBar.Small.Inverse</item>
+ <item name="progressBarStyleLargeInverse">@style/Widget.Material.Light.ProgressBar.Large.Inverse</item>
+ <item name="seekBarStyle">@style/Widget.Material.Light.SeekBar</item>
+ <item name="ratingBarStyle">@style/Widget.Material.Light.RatingBar</item>
+ <item name="ratingBarStyleIndicator">@style/Widget.Material.Light.RatingBar.Indicator</item>
+ <item name="ratingBarStyleSmall">@style/Widget.Material.Light.RatingBar.Small</item>
+ <item name="radioButtonStyle">@style/Widget.Material.Light.CompoundButton.RadioButton</item>
+ <item name="scrollViewStyle">@style/Widget.Material.Light.ScrollView</item>
+ <item name="horizontalScrollViewStyle">@style/Widget.Material.Light.HorizontalScrollView</item>
+ <item name="spinnerStyle">?attr/dropDownSpinnerStyle</item>
+ <item name="dropDownSpinnerStyle">@style/Widget.Material.Light.Spinner.DropDown</item>
+ <item name="starStyle">@style/Widget.Material.Light.CompoundButton.Star</item>
+ <item name="tabWidgetStyle">@style/Widget.Material.Light.TabWidget</item>
+ <item name="textViewStyle">@style/Widget.Material.Light.TextView</item>
+ <item name="errorMessageBackground">@drawable/popup_inline_error_holo_light</item>
+ <item name="errorMessageAboveBackground">@drawable/popup_inline_error_above_holo_light</item>
+ <item name="webTextViewStyle">@style/Widget.Material.Light.WebTextView</item>
+ <item name="webViewStyle">@style/Widget.Material.Light.WebView</item>
+ <item name="dropDownItemStyle">@style/Widget.Material.Light.DropDownItem</item>
+ <item name="spinnerDropDownItemStyle">@style/Widget.Material.Light.DropDownItem.Spinner</item>
+ <item name="spinnerItemStyle">@style/Widget.Material.TextView.SpinnerItem</item>
+ <item name="dropDownHintAppearance">@style/TextAppearance.Material.Widget.DropDownHint</item>
+ <item name="keyboardViewStyle">@style/Widget.Material.KeyboardView</item>
+ <item name="quickContactBadgeStyleWindowSmall">@style/Widget.Material.QuickContactBadge.WindowSmall</item>
+ <item name="quickContactBadgeStyleWindowMedium">@style/Widget.Material.QuickContactBadge.WindowMedium</item>
+ <item name="quickContactBadgeStyleWindowLarge">@style/Widget.Material.QuickContactBadge.WindowLarge</item>
+ <item name="quickContactBadgeStyleSmallWindowSmall">@style/Widget.Material.QuickContactBadgeSmall.WindowSmall</item>
+ <item name="quickContactBadgeStyleSmallWindowMedium">@style/Widget.Material.QuickContactBadgeSmall.WindowMedium</item>
+ <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Material.QuickContactBadgeSmall.WindowLarge</item>
+ <item name="listPopupWindowStyle">@style/Widget.Material.Light.ListPopupWindow</item>
+ <item name="popupMenuStyle">@style/Widget.Material.Light.PopupMenu</item>
+ <item name="stackViewStyle">@style/Widget.Material.Light.StackView</item>
+ <item name="activityChooserViewStyle">@style/Widget.Material.Light.ActivityChooserView</item>
+
+ <!-- Preference styles -->
+ <item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item>
+ <item name="preferenceFragmentStyle">@style/PreferenceFragment.Material</item>
+ <item name="preferenceCategoryStyle">@style/Preference.Material.Category</item>
+ <item name="preferenceStyle">@style/Preference.Material</item>
+ <item name="preferenceInformationStyle">@style/Preference.Material.Information</item>
+ <item name="checkBoxPreferenceStyle">@style/Preference.Material.CheckBoxPreference</item>
+ <item name="switchPreferenceStyle">@style/Preference.Material.SwitchPreference</item>
+ <item name="seekBarPreferenceStyle">@style/Preference.Material.SeekBarPreference</item>
+ <item name="yesNoPreferenceStyle">@style/Preference.Material.DialogPreference.YesNoPreference</item>
+ <item name="dialogPreferenceStyle">@style/Preference.Material.DialogPreference</item>
+ <item name="editTextPreferenceStyle">@style/Preference.Material.DialogPreference.EditTextPreference</item>
+ <item name="ringtonePreferenceStyle">@style/Preference.Material.RingtonePreference</item>
+ <item name="preferenceLayoutChild">@layout/preference_child_material</item>
+ <item name="preferencePanelStyle">@style/PreferencePanel.Material</item>
+ <item name="preferenceHeaderPanelStyle">@style/PreferenceHeaderPanel.Material</item>
+ <item name="preferenceListStyle">@style/PreferenceHeaderList.Material</item>
+ <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Material</item>
+ <item name="preferenceFragmentPaddingSide">@dimen/preference_fragment_padding_side_material</item>
+ <item name="detailsElementBackground">?attr/colorBackground</item>
+
+ <!-- PreferenceFrameLayout attributes -->
+ <item name="preferenceFrameLayoutStyle">@style/Widget.Material.PreferenceFrameLayout</item>
+
+ <!-- Search widget styles -->
+ <item name="searchWidgetCorpusItemBackground">@color/search_widget_corpus_item_background</item>
+
+ <!-- Action bar styles -->
+ <item name="actionDropDownStyle">@style/Widget.Material.Light.Spinner.DropDown.ActionBar</item>
+ <item name="actionButtonStyle">@style/Widget.Material.Light.ActionButton</item>
+ <item name="actionOverflowButtonStyle">@style/Widget.Material.Light.ActionButton.Overflow</item>
+ <item name="actionOverflowMenuStyle">@android:style/Widget.Material.Light.PopupMenu.Overflow</item>
+ <item name="actionModeBackground">@drawable/cab_background_top_holo_light</item>
+ <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
+ <item name="actionModeCloseDrawable">@drawable/ic_cab_done_material</item>
+ <item name="actionBarTabStyle">@style/Widget.Material.Light.ActionBar.TabView</item>
+ <item name="actionBarTabBarStyle">@style/Widget.Material.Light.ActionBar.TabBar</item>
+ <item name="actionBarTabTextStyle">@style/Widget.Material.Light.ActionBar.TabText</item>
+ <item name="actionModeStyle">@style/Widget.Material.Light.ActionMode</item>
+ <item name="actionModeCloseButtonStyle">@style/Widget.Material.Light.ActionButton.CloseMode</item>
+ <item name="actionBarStyle">@style/Widget.Material.Light.ActionBar.Solid</item>
+ <item name="actionBarSize">@dimen/action_bar_default_height_material</item>
+ <item name="actionModePopupWindowStyle">@style/Widget.Material.Light.PopupWindow.ActionMode</item>
+ <item name="actionBarWidgetTheme">@null</item>
+ <item name="actionBarTheme">@style/ThemeOverlay.Material.ActionBar</item>
+ <item name="actionBarItemBackground">?attr/selectableItemBackgroundBorderless</item>
+
+ <item name="actionModeCutDrawable">@drawable/ic_menu_cut_material</item>
+ <item name="actionModeCopyDrawable">@drawable/ic_menu_copy_material</item>
+ <item name="actionModePasteDrawable">@drawable/ic_menu_paste_material</item>
+ <item name="actionModeSelectAllDrawable">@drawable/ic_menu_selectall_material</item>
+ <item name="actionModeShareDrawable">@drawable/ic_menu_share_material</item>
+ <item name="actionModeFindDrawable">@drawable/ic_menu_find_material</item>
+ <item name="actionModeWebSearchDrawable">@drawable/ic_menu_search_material</item>
+
+ <item name="toolbarStyle">@style/Widget.Material.Toolbar</item>
+
+ <item name="dividerVertical">?attr/listDivider</item>
+ <item name="dividerHorizontal">?attr/listDivider</item>
+ <item name="buttonBarStyle">@style/Widget.Material.Light.ButtonBar</item>
+ <item name="buttonBarButtonStyle">@style/Widget.Material.Light.Button.Borderless</item>
+ <item name="segmentedButtonStyle">@style/Widget.Material.Light.SegmentedButton</item>
+
+ <!-- SearchView attributes -->
+ <item name="searchDropdownBackground">?attr/colorBackground</item>
+ <item name="searchViewTextField">@drawable/textfield_search_material</item>
+ <item name="searchViewTextFieldRight">@drawable/textfield_search_material</item>
+ <item name="searchViewCloseIcon">@android:drawable/ic_clear_material</item>
+ <item name="searchViewSearchIcon">@android:drawable/ic_search_api_material</item>
+ <item name="searchViewGoIcon">@android:drawable/ic_go_search_api_material</item>
+ <item name="searchViewVoiceIcon">@android:drawable/ic_voice_search_api_material</item>
+ <item name="searchViewEditQuery">@android:drawable/ic_commit_search_api_material</item>
+
+ <item name="searchDialogTheme">@style/Theme.Material.Light.SearchBar</item>
+
+ <!-- NumberPicker style-->
+ <item name="numberPickerStyle">@style/Widget.Material.Light.NumberPicker</item>
+
+ <!-- CalendarView style-->
+ <item name="calendarViewStyle">@style/Widget.Material.Light.CalendarView</item>
+
+ <!-- TimePicker style -->
+ <item name="timePickerStyle">@style/Widget.Material.Light.TimePicker</item>
+
+ <!-- TimePicker Header background color -->
+ <item name="timePickerHeaderBackgroundColor">?attr/colorBackground</item>
+
+ <!-- TimePicker Header time label text appearance -->
+ <item name="timePickerHeaderTimeLabelTextAppearance">@style/TextAppearance.Material.TimePicker.TimeLabel</item>
+
+ <!-- TimePicker Header am pm label text appearance -->
+ <item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.Material.TimePicker.AmPmLabel</item>
+
+ <!-- TimePicker dialog theme -->
+ <item name="timePickerDialogTheme">@style/Theme.Material.Light.Dialog.TimePicker</item>
+
+ <!-- DatePicker style -->
+ <item name="datePickerStyle">@style/Widget.Material.Light.DatePicker</item>
+
+ <item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_material</item>
+ <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_light</item>
+ <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_light</item>
+ <item name="fastScrollTrackDrawable">@drawable/fastscroll_track_material</item>
+ <item name="fastScrollOverlayPosition">atThumb</item>
+
+ <!-- Color palette -->
+ <item name="colorPrimaryDark">@color/material_blue_grey_600</item>
+ <item name="colorPrimary">@color/material_blue_grey_400</item>
+ <item name="colorAccent">@color/material_light_blue_A200</item>
+
+ <item name="colorControlNormal">?attr/textColorSecondary</item>
+ <item name="colorControlActivated">?attr/colorAccent</item>
+
+ <item name="colorControlHighlight">@color/ripple_material_light</item>
+ <item name="colorButtonNormal">@color/btn_default_material_light</item>
+ </style>
+
+ <!-- Variant of the material (light) theme that has a solid (opaque) action bar
+ with an inverse color profile. The dark action bar sharply stands out against
+ the light content. -->
+ <style name="Theme.Material.Light.DarkActionBar">
+ <item name="actionBarWidgetTheme">@null</item>
+ <item name="actionBarTheme">@style/ThemeOverlay.Material.Dark.ActionBar</item>
+
+ <item name="colorPrimaryDark">@color/material_blue_grey_900</item>
+ <item name="colorPrimary">@color/material_blue_grey_800</item>
+ </style>
+
+ <style name="ThemeOverlay" />
+ <style name="ThemeOverlay.Material" />
+
+ <!-- Theme overlay that replaces colors with their light versions but preserves
+ the value of colorAccent, colorPrimary and its variants. -->
+ <style name="ThemeOverlay.Material.Light">
+ <item name="colorForeground">@color/bright_foreground_material_light</item>
+ <item name="colorForegroundInverse">@color/bright_foreground_material_dark</item>
+ <item name="colorBackground">@color/background_material_light</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
+
+ <item name="textColorPrimary">@color/primary_text_material_light</item>
+ <item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
+ <item name="textColorSecondary">@color/secondary_text_material_light</item>
+ <item name="textColorSecondaryInverse">@color/secondary_text_material_dark</item>
+ <item name="textColorTertiary">@color/tertiary_text_material_light</item>
+ <item name="textColorTertiaryInverse">@color/tertiary_text_material_dark</item>
+ <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_light</item>
+ <item name="textColorPrimaryInverseDisableOnly">@color/primary_text_disable_only_material_dark</item>
+ <item name="textColorHint">@color/hint_foreground_material_light</item>
+ <item name="textColorHintInverse">@color/hint_foreground_material_dark</item>
+ <item name="textColorHighlight">@color/highlighted_text_material_light</item>
+ <item name="textColorHighlightInverse">@color/highlighted_text_material_dark</item>
+ <item name="textColorLink">@color/material_teal_500</item>
+ <item name="textColorLinkInverse">@color/material_teal_500</item>
+ <item name="textColorSearchUrl">@color/search_url_text_material_light</item>
+ <item name="textColorAlertDialogListItem">@color/primary_text_material_light</item>
+
+ <item name="textCheckMark">@drawable/indicator_check_mark_light</item>
+ <item name="textCheckMarkInverse">@drawable/indicator_check_mark_dark</item>
+
+ <item name="windowBackground">@color/background_material_light</item>
+
+ <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_light</item>
+ <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_light</item>
+
+ <item name="colorControlHighlight">@color/ripple_material_light</item>
+ <item name="colorButtonNormal">@color/btn_default_material_light</item>
+ </style>
+
+ <!-- Theme overlay that replaces colors with their dark versions but preserves
+ the value of colorAccent, colorPrimary and its variants. -->
+ <style name="ThemeOverlay.Material.Dark">
+ <item name="colorForeground">@color/bright_foreground_material_dark</item>
+ <item name="colorForegroundInverse">@color/bright_foreground_material_light</item>
+ <item name="colorBackground">@color/background_material_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
+
+ <item name="textColorPrimary">@color/primary_text_material_dark</item>
+ <item name="textColorPrimaryInverse">@color/primary_text_material_light</item>
+ <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_dark</item>
+ <item name="textColorSecondary">@color/secondary_text_material_dark</item>
+ <item name="textColorSecondaryInverse">@color/secondary_text_material_light</item>
+ <item name="textColorTertiary">@color/tertiary_text_material_dark</item>
+ <item name="textColorTertiaryInverse">@color/tertiary_text_material_light</item>
+ <item name="textColorHint">@color/hint_foreground_material_dark</item>
+ <item name="textColorHintInverse">@color/hint_foreground_material_light</item>
+ <item name="textColorHighlight">@color/highlighted_text_material_dark</item>
+ <item name="textColorHighlightInverse">@color/highlighted_text_material_light</item>
+ <item name="textColorLink">@color/material_teal_500</item>
+ <item name="textColorLinkInverse">@color/material_teal_500</item>
+ <item name="textColorSearchUrl">@color/search_url_text_material_dark</item>
+ <item name="textColorAlertDialogListItem">@color/primary_text_material_dark</item>
+
+ <item name="textCheckMark">@drawable/indicator_check_mark_dark</item>
+ <item name="textCheckMarkInverse">@drawable/indicator_check_mark_light</item>
+
+ <item name="windowBackground">@color/background_material_dark</item>
+
+ <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_dark</item>
+ <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_dark</item>
+
+ <item name="colorControlHighlight">@color/ripple_material_dark</item>
+ <item name="colorButtonNormal">@color/btn_default_material_dark</item>
+ </style>
+
+ <!-- Theme overlay that replaces the normal control color, which by default is the same as the
+ secondary text color, with the primary text color. -->
+ <style name="ThemeOverlay.Material.ActionBar">
+ <item name="colorControlNormal">?attr/textColorPrimary</item>
+ </style>
+
+ <!-- Theme overlay that replaces colors with their dark versions and replaces the normal
+ control color, which by default is the same as the secondary text color, with the primary
+ text color. -->
+ <style name="ThemeOverlay.Material.Dark.ActionBar">
+ <item name="colorControlNormal">?attr/textColorPrimary</item>
+ </style>
+
+ <!-- Variant of the material (dark) theme with no action bar. -->
+ <style name="Theme.Material.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ </style>
+
+ <!-- Variant of the material (dark) theme that has no title bar and fills
+ the entire screen. This theme
+ sets {@link android.R.attr#windowFullscreen} to true. -->
+ <style name="Theme.Material.NoActionBar.Fullscreen">
+ <item name="windowFullscreen">true</item>
+ <item name="windowContentOverlay">@null</item>
+ </style>
+
+ <!-- Variant of the material (dark) theme that has no title bar and fills
+ the entire screen and extends into the display overscan region. This theme
+ sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
+ to true. -->
+ <style name="Theme.Material.NoActionBar.Overscan">
+ <item name="windowFullscreen">true</item>
+ <item name="windowOverscan">true</item>
+ <item name="windowContentOverlay">@null</item>
+ </style>
+
+ <!-- Variant of the material (dark) theme that has no title bar and translucent
+ system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
+ {@link android.R.attr#windowTranslucentNavigation} to true. -->
+ <style name="Theme.Material.NoActionBar.TranslucentDecor">
+ <item name="windowTranslucentStatus">true</item>
+ <item name="windowTranslucentNavigation">true</item>
+ <item name="windowContentOverlay">@null</item>
+ </style>
+
+ <!-- Variant of the material (light) theme with no action bar. -->
+ <style name="Theme.Material.Light.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ </style>
+
+ <!-- Variant of the material (light) theme that has no title bar and fills
+ the entire screen. This theme
+ sets {@link android.R.attr#windowFullscreen} to true. -->
+ <style name="Theme.Material.Light.NoActionBar.Fullscreen">
+ <item name="windowFullscreen">true</item>
+ <item name="windowContentOverlay">@null</item>
+ </style>
+
+ <!-- Variant of the material (light) theme that has no title bar and fills
+ the entire screen and extends into the display overscan region. This theme
+ sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
+ to true. -->
+ <style name="Theme.Material.Light.NoActionBar.Overscan">
+ <item name="windowFullscreen">true</item>
+ <item name="windowOverscan">true</item>
+ <item name="windowContentOverlay">@null</item>
+ </style>
+
+ <!-- Variant of the material (light) theme that has no title bar and translucent
+ system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
+ {@link android.R.attr#windowTranslucentNavigation} to true. -->
+ <style name="Theme.Material.Light.NoActionBar.TranslucentDecor">
+ <item name="windowTranslucentStatus">true</item>
+ <item name="windowTranslucentNavigation">true</item>
+ <item name="windowContentOverlay">@null</item>
+ </style>
+
+ <!-- Default material dark theme for panel windows. This removes all extraneous
+ window decorations, so you basically have an empty rectangle in which
+ to place your content. It makes the window floating, with a transparent
+ background, and turns off dimming behind the window. -->
+ <style name="Theme.Material.Panel">
+ <item name="windowBackground">@color/transparent</item>
+ <item name="colorBackgroundCacheHint">@null</item>
+ <item name="windowFrame">@null</item>
+ <item name="windowContentOverlay">@null</item>
+ <item name="windowAnimationStyle">@null</item>
+ <item name="windowIsFloating">true</item>
+ <item name="backgroundDimEnabled">false</item>
+ <item name="windowIsTranslucent">true</item>
+ <item name="windowNoTitle">true</item>
+ </style>
+
+ <!-- Default material light theme for panel windows. This removes all extraneous
+ window decorations, so you basically have an empty rectangle in which
+ to place your content. It makes the window floating, with a transparent
+ background, and turns off dimming behind the window. -->
+ <style name="Theme.Material.Light.Panel">
+ <item name="windowBackground">@color/transparent</item>
+ <item name="colorBackgroundCacheHint">@null</item>
+ <item name="windowFrame">@null</item>
+ <item name="windowContentOverlay">@null</item>
+ <item name="windowAnimationStyle">@null</item>
+ <item name="windowIsFloating">true</item>
+ <item name="backgroundDimEnabled">false</item>
+ <item name="windowIsTranslucent">true</item>
+ <item name="windowNoTitle">true</item>
+ </style>
+
+ <!-- Material theme for an activity that is to be used for voice interaction.
+ This gives the activity a floating dialog style, to incorporate with the
+ system voice experience. -->
+ <style name="Theme.Material.Voice" parent="@style/Theme.Material.Dialog">
+ <item name="windowAnimationStyle">@style/Animation.VoiceActivity</item>
+ <item name="backgroundDimEnabled">false</item>
+ </style>
+
+ <!-- Material light theme for an activity that is to be used for voice interaction.
+ This gives the activity a floating dialog style, to incorporate with the
+ system voice experience. -->
+ <style name="Theme.Material.Light.Voice" parent="@style/Theme.Material.Light.Dialog">
+ <item name="windowAnimationStyle">@style/Animation.VoiceActivity</item>
+ <item name="backgroundDimEnabled">false</item>
+ </style>
+
+ <!-- Default theme for material style input methods, which is used by the
+ {@link android.inputmethodservice.InputMethodService} class.
+ this inherits from Theme.Panel, but sets up IME appropriate animations
+ and a few custom attributes. -->
+ <style name="Theme.Material.InputMethod" parent="Theme.Material.Light.Panel">
+ <item name="windowAnimationStyle">@style/Animation.InputMethod</item>
+ <item name="imeFullscreenBackground">@drawable/screen_background_selector_light</item>
+ <item name="imeExtractEnterAnimation">@anim/input_method_extract_enter</item>
+ <item name="imeExtractExitAnimation">@anim/input_method_extract_exit</item>
+ </style>
+
+ <!-- Default theme for material style voice interaction, which is used by the
+ {@link android.service.voice.VoiceInteractionSession} class.
+ this inherits from Theme.Panel, but sets up appropriate animations
+ and a few custom attributes. -->
+ <style name="Theme.Material.VoiceInteractionSession" parent="Theme.Material.Light.Panel">
+ <item name="windowAnimationStyle">@style/Animation.VoiceInteractionSession</item>
+ </style>
+
+ <!-- Theme for the search input bar. -->
+
+ <style name="Theme.Material.SearchBar" parent="Theme.Material.Panel">
+ <item name="actionModeBackground">@drawable/cab_background_top_holo_dark</item>
+ <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
+ </style>
+
+ <style name="Theme.Material.Light.SearchBar" parent="Theme.Material.Light.Panel">
+ <item name="actionModeBackground">@drawable/cab_background_top_holo_light</item>
+ <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
+ </style>
+
+ <!-- Menu Themes -->
+ <eat-comment />
+
+ <style name="Theme.Material.CompactMenu">
+ <!-- Menu/item attributes -->
+ <item name="itemTextAppearance">?attr/textAppearanceMedium</item>
+ <item name="listViewStyle">@style/Widget.Material.ListView</item>
+ <item name="windowAnimationStyle">@style/Animation.DropDownUp</item>
+ <item name="background">@null</item>
+ </style>
+
+ <style name="Theme.Material.Light.CompactMenu">
+ <!-- Menu/item attributes -->
+ <item name="itemTextAppearance">?attr/textAppearanceMedium</item>
+ <item name="listViewStyle">@style/Widget.Material.Light.ListView</item>
+ <item name="windowAnimationStyle">@style/Animation.DropDownUp</item>
+ <item name="background">@null</item>
+ </style>
+
+ <!-- Dialog themes for Material -->
+ <eat-comment />
+
+ <!-- Material theme for dialog windows and activities, which is used by the
+ {@link android.app.Dialog} class. This changes the window to be
+ floating (not fill the entire screen), and puts a frame around its
+ contents. You can set this theme on an activity if you would like to
+ make an activity that looks like a Dialog. -->
+ <style name="Theme.Material.Dialog">
+ <item name="windowFrame">@null</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
+ <item name="windowBackground">@drawable/dialog_background_shadow_material</item>
+ <item name="windowIsFloating">true</item>
+ <item name="windowContentOverlay">@null</item>
+ <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
+ <item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
+ <item name="windowActionBar">false</item>
+ <item name="windowActionModeOverlay">true</item>
+ <item name="windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
+
+ <item name="colorBackgroundCacheHint">@null</item>
+
+ <item name="buttonBarStyle">@style/Widget.Material.ButtonBar.AlertDialog</item>
+ <item name="borderlessButtonStyle">@style/Widget.Material.Button.Borderless</item>
+
+ <item name="textAppearance">@style/TextAppearance.Material</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
+
+ <item name="listPreferredItemPaddingLeft">16dip</item>
+ <item name="listPreferredItemPaddingRight">16dip</item>
+ <item name="listPreferredItemPaddingStart">16dip</item>
+ <item name="listPreferredItemPaddingEnd">16dip</item>
+
+ <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+ </style>
+
+ <!-- Variant of Theme.Material.Dialog that has a nice minimum width for
+ a regular dialog. -->
+ <style name="Theme.Material.Dialog.MinWidth">
+ <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+ <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
+ </style>
+
+ <!-- Variant of Theme.Material.Dialog that does not include a title bar. -->
+ <style name="Theme.Material.Dialog.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ </style>
+
+ <!-- Variant of Theme.Material.Dialog.NoActionBar that has a nice minimum width for
+ a regular dialog. -->
+ <style name="Theme.Material.Dialog.NoActionBar.MinWidth">
+ <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+ <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
+ </style>
+
+ <!-- Variant of Theme.Material.Dialog that has a fixed size. -->
+ <style name="Theme.Material.Dialog.FixedSize">
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+ </style>
+
+ <!-- Variant of Theme.Material.Dialog.NoActionBar that has a fixed size. -->
+ <style name="Theme.Material.Dialog.NoActionBar.FixedSize">
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+ </style>
+
+ <!-- Variant of Theme.Material.Dialog that does not include a frame (or background).
+ The view hierarchy of the dialog is responsible for drawing all of
+ its pixels. -->
+ <style name="Theme.Material.Dialog.NoFrame">
+ <item name="windowBackground">@color/transparent</item>
+ <item name="windowAnimationStyle">@null</item>
+ <item name="backgroundDimEnabled">false</item>
+ <item name="windowIsTranslucent">true</item>
+ <item name="windowNoTitle">true</item>
+ <item name="windowCloseOnTouchOutside">false</item>
+ </style>
+
+ <!-- Material theme for alert dialog windows, which is used by the
+ {@link android.app.AlertDialog} class. This is basically a dialog
+ but sets the background to empty so it can do two-tone backgrounds.
+ For applications targeting Honeycomb or newer, this is the default
+ AlertDialog theme. -->
+ <style name="Theme.Material.Dialog.Alert">
+ <item name="windowBackground">@color/transparent</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
+ <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+ <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
+ </style>
+
+ <!-- Material theme for the TimePicker dialog windows, which is used by the
+ {@link android.app.TimePickerDialog} class. -->
+ <style name="Theme.Material.Dialog.TimePicker">
+ <item name="windowBackground">@color/transparent</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
+ <item name="windowContentOverlay">@null</item>
+ </style>
+
+ <!-- Theme for a window that will be displayed either full-screen on
+ smaller screens (small, normal) or as a dialog on larger screens
+ (large, xlarge). -->
+ <style name="Theme.Material.DialogWhenLarge" parent="@style/Theme.Material" />
+
+ <!-- Theme for a window without a title bar that will be displayed either
+ full-screen on smaller screens (small, normal) or as a dialog on larger screens
+ (large, xlarge). -->
+ <style name="Theme.Material.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.NoActionBar" />
+
+ <!-- Theme for a presentation window on a secondary display. -->
+ <style name="Theme.Material.Dialog.Presentation" parent="@style/Theme.Material.NoActionBar.Fullscreen" />
+
+ <!-- Light material dialog themes -->
+
+ <!-- Material light theme for dialog windows and activities, which is used by the
+ {@link android.app.Dialog} class. This changes the window to be
+ floating (not fill the entire screen), and puts a frame around its
+ contents. You can set this theme on an activity if you would like to
+ make an activity that looks like a Dialog. -->
+ <style name="Theme.Material.Light.Dialog">
+ <item name="windowFrame">@null</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Material.Light</item>
+ <item name="windowBackground">@drawable/dialog_background_shadow_material</item>
+ <item name="windowIsFloating">true</item>
+ <item name="windowContentOverlay">@null</item>
+ <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
+ <item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
+ <item name="windowActionBar">false</item>
+ <item name="windowActionModeOverlay">true</item>
+ <item name="windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
+
+ <item name="colorBackgroundCacheHint">@null</item>
+
+ <item name="buttonBarStyle">@style/Widget.Material.Light.ButtonBar.AlertDialog</item>
+ <item name="borderlessButtonStyle">@style/Widget.Material.Light.Button.Borderless</item>
+
+ <item name="textAppearance">@style/TextAppearance.Material</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
+
+ <item name="listPreferredItemPaddingLeft">16dip</item>
+ <item name="listPreferredItemPaddingRight">16dip</item>
+ <item name="listPreferredItemPaddingStart">16dip</item>
+ <item name="listPreferredItemPaddingEnd">16dip</item>
+
+ <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+ </style>
+
+ <!-- Variant of Theme.Material.Light.Dialog that has a nice minimum width for
+ a regular dialog. -->
+ <style name="Theme.Material.Light.Dialog.MinWidth">
+ <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+ <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
+ </style>
+
+ <!-- Variant of Theme.Material.Light.Dialog that does not include a title bar. -->
+ <style name="Theme.Material.Light.Dialog.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ </style>
+
+ <!-- Variant of Theme.Material.Light.Dialog.NoActionBar that has a nice minimum width for
+ a regular dialog. -->
+ <style name="Theme.Material.Light.Dialog.NoActionBar.MinWidth">
+ <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+ <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
+ </style>
+
+ <!-- Variant of Theme.Material.Light.Dialog that has a fixed size. -->
+ <style name="Theme.Material.Light.Dialog.FixedSize">
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+ </style>
+
+ <!-- Variant of Theme.Material.Light.Dialog.NoActionBar that has a fixed size. -->
+ <style name="Theme.Material.Light.Dialog.NoActionBar.FixedSize">
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+ </style>
+
+ <!-- Theme for a window that will be displayed either full-screen on
+ smaller screens (small, normal) or as a dialog on larger screens
+ (large, xlarge). -->
+ <style name="Theme.Material.Light.DialogWhenLarge" parent="@style/Theme.Material.Light" />
+
+ <!-- Theme for a window without an action bar that will be displayed either full-screen
+ on smaller screens (small, normal) or as a dialog on larger screens
+ (large, xlarge). -->
+ <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Light.NoActionBar" />
+
+ <!-- Material light theme for alert dialog windows, which is used by the
+ {@link android.app.AlertDialog} class. This is basically a dialog
+ but sets the background to empty so it can do two-tone backgrounds.
+ For applications targeting Honeycomb or newer, this is the default
+ AlertDialog theme. -->
+ <style name="Theme.Material.Light.Dialog.Alert">
+ <item name="windowBackground">@color/transparent</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Material.Light</item>
+ <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+ <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
+ </style>
+
+ <!-- Material Light theme for the TimePicker dialog windows, which is used by the
+ {@link android.app.TimePickerDialog} class. -->
+ <style name="Theme.Material.Light.Dialog.TimePicker">
+ <item name="windowBackground">@color/transparent</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Material.Light</item>
+ </style>
+
+ <!-- Theme for a presentation window on a secondary display. -->
+ <style name="Theme.Material.Light.Dialog.Presentation" parent="@style/Theme.Material.Light.NoActionBar.Fullscreen" />
+
+ <!-- Default material (dark) for windows that want to have the user's selected
+ wallpaper appear behind them. -->
+ <style name="Theme.Material.Wallpaper">
+ <item name="windowBackground">@color/transparent</item>
+ <item name="colorBackgroundCacheHint">@null</item>
+ <item name="windowShowWallpaper">true</item>
+ </style>
+
+ <!--Default material (dark) for windows that want to have the user's selected
+ wallpaper appear behind them and without an action bar. -->
+ <style name="Theme.Material.Wallpaper.NoTitleBar">
+ <item name="windowNoTitle">true</item>
+ </style>
+
+ <!-- Default theme for Settings and activities launched from Settings. -->
+ <style name="Theme.Material.Settings" parent="@style/Theme.Material.Light.DarkActionBar">
+ <item name="colorPrimary">@color/material_blue_grey_900</item>
+ <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
+ <item name="colorAccent">@color/material_dark_teal_A400</item>
+ </style>
+
+</resources>
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
deleted file mode 100644
index eda7174..0000000
--- a/core/res/res/values/themes_quantum.xml
+++ /dev/null
@@ -1,1232 +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.
--->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Quantum themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see themes_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-<resources>
-
- <!-- Quantum Paper theme (dark version).
- <p>If you want to ensure that your
- app consistently uses the Quantum theme at all times, you must explicitly declare it in your
- manifest. For example, {@code <application android:theme="@style/Theme.Quantum">}.
-
- <p>Styles used by the Quantum theme are named using the convention Type.Quantum.Etc
- (for example, {@code Widget.Quantum.Button} and {@code
- TextAppearance.Quantum.Widget.PopupMenu.Large}).
- Specific resources used by Quantum are named using the convention @type/foo_bar_baz_quantum
- with trailing _dark or _light specifiers if they are not shared between both light and
- dark versions of the theme. -->
- <style name="Theme.Quantum">
- <item name="colorForeground">@color/bright_foreground_quantum_dark</item>
- <item name="colorForegroundInverse">@color/bright_foreground_quantum_light</item>
- <item name="colorBackground">@color/background_quantum_dark</item>
- <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_quantum_dark</item>
- <item name="disabledAlpha">0.5</item>
- <item name="backgroundDimAmount">0.6</item>
-
- <!-- Text styles -->
- <item name="textAppearance">@style/TextAppearance.Quantum</item>
- <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Inverse</item>
-
- <item name="textColorPrimary">@color/primary_text_quantum_dark</item>
- <item name="textColorPrimaryInverse">@color/primary_text_quantum_light</item>
- <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_quantum_dark</item>
- <item name="textColorSecondary">@color/secondary_text_quantum_dark</item>
- <item name="textColorSecondaryInverse">@color/secondary_text_quantum_light</item>
- <item name="textColorTertiary">@color/tertiary_text_quantum_dark</item>
- <item name="textColorTertiaryInverse">@color/tertiary_text_quantum_light</item>
- <item name="textColorHint">@color/hint_foreground_quantum_dark</item>
- <item name="textColorHintInverse">@color/hint_foreground_quantum_light</item>
- <item name="textColorHighlight">@color/highlighted_text_quantum_dark</item>
- <item name="textColorHighlightInverse">@color/highlighted_text_quantum_light</item>
- <item name="textColorLink">@color/quantum_teal_500</item>
- <item name="textColorLinkInverse">@color/quantum_teal_500</item>
- <item name="textColorSearchUrl">@color/search_url_text_quantum_dark</item>
- <item name="textColorAlertDialogListItem">@color/primary_text_quantum_dark</item>
-
- <item name="textAppearanceLarge">@style/TextAppearance.Quantum.Large</item>
- <item name="textAppearanceLargeInverse">@style/TextAppearance.Quantum.Large.Inverse</item>
- <item name="textAppearanceMedium">@style/TextAppearance.Quantum.Medium</item>
- <item name="textAppearanceMediumInverse">@style/TextAppearance.Quantum.Medium.Inverse</item>
- <item name="textAppearanceSmall">@style/TextAppearance.Quantum.Small</item>
- <item name="textAppearanceSmallInverse">@style/TextAppearance.Quantum.Small.Inverse</item>
- <item name="textAppearanceSearchResultTitle">@style/TextAppearance.Quantum.SearchResult.Title</item>
- <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.Quantum.SearchResult.Subtitle</item>
-
- <item name="textAppearanceButton">@style/TextAppearance.Quantum.Widget.Button</item>
-
- <item name="editTextColor">?attr/textColorPrimary</item>
- <item name="editTextBackground">@drawable/edit_text_quantum</item>
-
- <item name="candidatesTextStyleSpans">@string/candidates_style</item>
-
- <item name="textCheckMark">@drawable/indicator_check_mark_dark</item>
- <item name="textCheckMarkInverse">@drawable/indicator_check_mark_light</item>
-
- <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Quantum.Widget.PopupMenu.Large</item>
- <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Quantum.Widget.PopupMenu.Small</item>
-
- <!-- Button styles -->
- <item name="buttonStyle">@style/Widget.Quantum.Button</item>
- <item name="buttonStyleSmall">@style/Widget.Quantum.Button.Small</item>
- <item name="buttonStyleInset">@style/Widget.Quantum.Button.Inset</item>
- <item name="buttonStyleToggle">@style/Widget.Quantum.Button.Toggle</item>
-
- <item name="switchStyle">@style/Widget.Quantum.CompoundButton.Switch</item>
- <item name="mediaRouteButtonStyle">@style/Widget.Quantum.MediaRouteButton</item>
-
- <item name="selectableItemBackground">@drawable/item_background_quantum</item>
- <item name="selectableItemBackgroundBorderless">@drawable/item_background_borderless_quantum</item>
- <item name="borderlessButtonStyle">@style/Widget.Quantum.Button.Borderless</item>
- <item name="homeAsUpIndicator">@drawable/ic_ab_back_quantum</item>
-
- <!-- List attributes -->
- <item name="listPreferredItemHeight">64dip</item>
- <item name="listPreferredItemHeightSmall">48dip</item>
- <item name="listPreferredItemHeightLarge">80dip</item>
- <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
- <item name="textAppearanceListItem">@style/TextAppearance.Quantum.Subhead</item>
- <item name="textAppearanceListItemSmall">@style/TextAppearance.Quantum.Subhead</item>
- <item name="textAppearanceListItemSecondary">@style/TextAppearance.Quantum.Body1</item>
- <item name="listPreferredItemPaddingLeft">16dip</item>
- <item name="listPreferredItemPaddingRight">16dip</item>
- <item name="listPreferredItemPaddingStart">16dip</item>
- <item name="listPreferredItemPaddingEnd">16dip</item>
-
- <!-- @hide -->
- <item name="searchResultListItemHeight">58dip</item>
- <item name="listDivider">@drawable/list_divider_quantum</item>
- <item name="listSeparatorTextViewStyle">@style/Widget.Quantum.TextView.ListSeparator</item>
-
- <item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum_anim</item>
- <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
-
- <item name="listChoiceBackgroundIndicator">?attr/selectableItemBackground</item>
- <item name="activatedBackgroundIndicator">@drawable/activated_background_quantum</item>
-
- <item name="listDividerAlertDialog">@drawable/list_divider_quantum</item>
-
- <item name="expandableListPreferredItemPaddingLeft">40dip</item>
- <item name="expandableListPreferredChildPaddingLeft">?attr/expandableListPreferredItemPaddingLeft</item>
-
- <item name="expandableListPreferredItemIndicatorLeft">3dip</item>
- <item name="expandableListPreferredItemIndicatorRight">0dip</item>
- <item name="expandableListPreferredChildIndicatorLeft">?attr/expandableListPreferredItemIndicatorLeft</item>
- <item name="expandableListPreferredChildIndicatorRight">?attr/expandableListPreferredItemIndicatorRight</item>
- <item name="findOnPageNextDrawable">@drawable/ic_find_next_quantum</item>
- <item name="findOnPagePreviousDrawable">@drawable/ic_find_previous_quantum</item>
-
- <!-- Gallery attributes -->
- <item name="galleryItemBackground">@drawable/gallery_item_background</item>
-
- <!-- Window attributes -->
- <item name="windowBackground">@color/background_quantum_dark</item>
- <item name="windowFrame">@null</item>
- <item name="windowNoTitle">false</item>
- <item name="windowFullscreen">false</item>
- <item name="windowOverscan">false</item>
- <item name="windowIsFloating">false</item>
- <item name="windowContentOverlay">@null</item>
- <item name="windowShowWallpaper">false</item>
- <item name="windowTitleStyle">@style/WindowTitle.Quantum</item>
- <item name="windowTitleSize">25dip</item>
- <item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.Quantum</item>
- <item name="windowContentTransitions">false</item>
- <item name="windowAnimationStyle">@style/Animation.Quantum.Activity</item>
- <item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
- <item name="windowActionBar">true</item>
- <item name="windowActionModeOverlay">false</item>
- <item name="windowDrawsSystemBarBackgrounds">true</item>
- <item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
- <item name="statusBarColor">?attr/colorPrimaryDark</item>
- <item name="navigationBarColor">@color/black</item>
- <item name="windowEnterTransition">@transition/fade</item>
- <item name="windowSharedElementEnterTransition">@transition/move</item>
- <item name="windowSharedElementExitTransition">@transition/move</item>
-
- <!-- Dialog attributes -->
- <item name="dialogTheme">@style/Theme.Quantum.Dialog</item>
- <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_quantum</item>
- <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_quantum</item>
- <item name="dialogTitleDecorLayout">@layout/dialog_title_quantum</item>
-
- <!-- AlertDialog attributes -->
- <item name="alertDialogTheme">@style/Theme.Quantum.Dialog.Alert</item>
- <item name="alertDialogStyle">@style/AlertDialog.Quantum</item>
- <item name="alertDialogCenterButtons">false</item>
- <item name="alertDialogIcon">@drawable/ic_dialog_alert_quantum</item>
-
- <!-- Presentation attributes -->
- <item name="presentationTheme">@style/Theme.Quantum.Dialog.Presentation</item>
-
- <!-- Toast attributes -->
- <item name="toastFrameBackground">@drawable/toast_frame</item>
-
- <!-- Panel attributes -->
- <item name="panelBackground">?attr/colorBackground</item>
- <item name="panelFullBackground">@drawable/menu_background_fill_parent_width</item>
- <!-- These three attributes do not seems to be used by the framework. Declared public though -->
- <item name="panelColorBackground">#000</item>
- <item name="panelColorForeground">?attr/textColorPrimary</item>
- <item name="panelTextAppearance">?attr/textAppearance</item>
-
- <item name="panelMenuIsCompact">true</item>
- <item name="panelMenuListWidth">250dip</item>
- <item name="panelMenuListTheme">@style/Theme.Quantum.CompactMenu</item>
-
- <!-- Scrollbar attributes -->
- <item name="scrollbarFadeDuration">250</item>
- <item name="scrollbarDefaultDelayBeforeFade">300</item>
- <item name="scrollbarSize">10dip</item>
- <item name="scrollbarThumbHorizontal">@drawable/scrollbar_handle_quantum</item>
- <item name="scrollbarThumbVertical">@drawable/scrollbar_handle_quantum</item>
- <item name="scrollbarTrackHorizontal">@null</item>
- <item name="scrollbarTrackVertical">@null</item>
-
- <!-- Text selection handle attributes -->
- <item name="textSelectHandleLeft">@drawable/text_select_handle_left_quantum</item>
- <item name="textSelectHandleRight">@drawable/text_select_handle_right_quantum</item>
- <item name="textSelectHandle">@drawable/text_select_handle_middle_quantum</item>
- <item name="textSelectHandleWindowStyle">@style/Widget.Quantum.TextSelectHandle</item>
- <item name="textSuggestionsWindowStyle">@style/Widget.Quantum.TextSuggestionsPopupWindow</item>
- <item name="textCursorDrawable">@drawable/text_cursor_quantum</item>
-
- <!-- Widget styles -->
- <item name="absListViewStyle">@style/Widget.Quantum.AbsListView</item>
- <item name="autoCompleteTextViewStyle">@style/Widget.Quantum.AutoCompleteTextView</item>
- <item name="checkboxStyle">@style/Widget.Quantum.CompoundButton.CheckBox</item>
- <item name="checkedTextViewStyle">@style/Widget.Quantum.CheckedTextView</item>
- <item name="dropDownListViewStyle">@style/Widget.Quantum.ListView.DropDown</item>
- <item name="editTextStyle">@style/Widget.Quantum.EditText</item>
- <item name="expandableListViewStyle">@style/Widget.Quantum.ExpandableListView</item>
- <item name="expandableListViewWhiteStyle">@style/Widget.Quantum.ExpandableListView.White</item>
- <item name="fastScrollStyle">@style/Widget.Quantum.FastScroll</item>
- <item name="galleryStyle">@style/Widget.Quantum.Gallery</item>
- <item name="gestureOverlayViewStyle">@style/Widget.Quantum.GestureOverlayView</item>
- <item name="gridViewStyle">@style/Widget.Quantum.GridView</item>
- <item name="imageButtonStyle">@style/Widget.Quantum.ImageButton</item>
- <item name="imageWellStyle">@style/Widget.Quantum.ImageWell</item>
- <item name="listViewStyle">@style/Widget.Quantum.ListView</item>
- <item name="listViewWhiteStyle">@style/Widget.Quantum.ListView.White</item>
- <item name="popupWindowStyle">@style/Widget.Quantum.PopupWindow</item>
- <item name="progressBarStyle">@style/Widget.Quantum.ProgressBar</item>
- <item name="progressBarStyleHorizontal">@style/Widget.Quantum.ProgressBar.Horizontal</item>
- <item name="progressBarStyleSmall">@style/Widget.Quantum.ProgressBar.Small</item>
- <item name="progressBarStyleSmallTitle">@style/Widget.Quantum.ProgressBar.Small.Title</item>
- <item name="progressBarStyleLarge">@style/Widget.Quantum.ProgressBar.Large</item>
- <item name="progressBarStyleInverse">@style/Widget.Quantum.ProgressBar.Inverse</item>
- <item name="progressBarStyleSmallInverse">@style/Widget.Quantum.ProgressBar.Small.Inverse</item>
- <item name="progressBarStyleLargeInverse">@style/Widget.Quantum.ProgressBar.Large.Inverse</item>
- <item name="seekBarStyle">@style/Widget.Quantum.SeekBar</item>
- <item name="ratingBarStyle">@style/Widget.Quantum.RatingBar</item>
- <item name="ratingBarStyleIndicator">@style/Widget.Quantum.RatingBar.Indicator</item>
- <item name="ratingBarStyleSmall">@style/Widget.Quantum.RatingBar.Small</item>
- <item name="radioButtonStyle">@style/Widget.Quantum.CompoundButton.RadioButton</item>
- <item name="scrollViewStyle">@style/Widget.Quantum.ScrollView</item>
- <item name="horizontalScrollViewStyle">@style/Widget.Quantum.HorizontalScrollView</item>
- <item name="spinnerStyle">?attr/dropDownSpinnerStyle</item>
- <item name="dropDownSpinnerStyle">@style/Widget.Quantum.Spinner.DropDown</item>
- <item name="starStyle">@style/Widget.Quantum.CompoundButton.Star</item>
- <item name="tabWidgetStyle">@style/Widget.Quantum.TabWidget</item>
- <item name="textViewStyle">@style/Widget.Quantum.TextView</item>
- <item name="errorMessageBackground">@drawable/popup_inline_error_holo_dark</item>
- <item name="errorMessageAboveBackground">@drawable/popup_inline_error_above_holo_dark</item>
- <item name="webTextViewStyle">@style/Widget.Quantum.WebTextView</item>
- <item name="webViewStyle">@style/Widget.Quantum.WebView</item>
- <item name="dropDownItemStyle">@style/Widget.Quantum.DropDownItem</item>
- <item name="spinnerDropDownItemStyle">@style/Widget.Quantum.DropDownItem.Spinner</item>
- <item name="spinnerItemStyle">@style/Widget.Quantum.TextView.SpinnerItem</item>
- <item name="dropDownHintAppearance">@style/TextAppearance.Quantum.Widget.DropDownHint</item>
- <item name="keyboardViewStyle">@style/Widget.Quantum.KeyboardView</item>
- <item name="quickContactBadgeStyleWindowSmall">@style/Widget.Quantum.QuickContactBadge.WindowSmall</item>
- <item name="quickContactBadgeStyleWindowMedium">@style/Widget.Quantum.QuickContactBadge.WindowMedium</item>
- <item name="quickContactBadgeStyleWindowLarge">@style/Widget.Quantum.QuickContactBadge.WindowLarge</item>
- <item name="quickContactBadgeStyleSmallWindowSmall">@style/Widget.Quantum.QuickContactBadgeSmall.WindowSmall</item>
- <item name="quickContactBadgeStyleSmallWindowMedium">@style/Widget.Quantum.QuickContactBadgeSmall.WindowMedium</item>
- <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Quantum.QuickContactBadgeSmall.WindowLarge</item>
- <item name="listPopupWindowStyle">@style/Widget.Quantum.ListPopupWindow</item>
- <item name="popupMenuStyle">@style/Widget.Quantum.PopupMenu</item>
- <item name="stackViewStyle">@style/Widget.Quantum.StackView</item>
- <item name="activityChooserViewStyle">@style/Widget.Quantum.ActivityChooserView</item>
-
- <!-- Preference styles -->
- <item name="preferenceScreenStyle">@style/Preference.Quantum.PreferenceScreen</item>
- <item name="preferenceFragmentStyle">@style/PreferenceFragment.Quantum</item>
- <item name="preferenceFragmentPaddingSide">0dip</item>
- <item name="preferenceCategoryStyle">@style/Preference.Quantum.Category</item>
- <item name="preferenceStyle">@style/Preference.Quantum</item>
- <item name="preferenceInformationStyle">@style/Preference.Quantum.Information</item>
- <item name="checkBoxPreferenceStyle">@style/Preference.Quantum.CheckBoxPreference</item>
- <item name="switchPreferenceStyle">@style/Preference.Quantum.SwitchPreference</item>
- <item name="yesNoPreferenceStyle">@style/Preference.Quantum.DialogPreference.YesNoPreference</item>
- <item name="dialogPreferenceStyle">@style/Preference.Quantum.DialogPreference</item>
- <item name="editTextPreferenceStyle">@style/Preference.Quantum.DialogPreference.EditTextPreference</item>
- <item name="ringtonePreferenceStyle">@style/Preference.Quantum.RingtonePreference</item>
- <item name="preferenceLayoutChild">@layout/preference_child_quantum</item>
- <item name="detailsElementBackground">?attr/colorBackground</item>
-
- <!-- Search widget styles -->
- <item name="searchWidgetCorpusItemBackground">@color/search_widget_corpus_item_background</item>
-
- <!-- Action bar styles -->
- <item name="actionDropDownStyle">@style/Widget.Quantum.Spinner.DropDown.ActionBar</item>
- <item name="actionButtonStyle">@style/Widget.Quantum.ActionButton</item>
- <item name="actionOverflowButtonStyle">@style/Widget.Quantum.ActionButton.Overflow</item>
- <item name="actionOverflowMenuStyle">@android:style/Widget.Quantum.PopupMenu.Overflow</item>
- <item name="actionModeBackground">?attr/colorPrimaryDark</item>
- <item name="actionModeSplitBackground">?attr/colorPrimaryDark</item>
- <item name="actionModeCloseDrawable">@drawable/ic_cab_done_quantum</item>
- <item name="actionBarTabStyle">@style/Widget.Quantum.ActionBar.TabView</item>
- <item name="actionBarTabBarStyle">@style/Widget.Quantum.ActionBar.TabBar</item>
- <item name="actionBarTabTextStyle">@style/Widget.Quantum.ActionBar.TabText</item>
- <item name="actionModeStyle">@style/Widget.Quantum.ActionMode</item>
- <item name="actionModeCloseButtonStyle">@style/Widget.Quantum.ActionButton.CloseMode</item>
- <item name="actionBarStyle">@style/Widget.Quantum.ActionBar.Solid</item>
- <item name="actionBarSize">@dimen/action_bar_default_height_quantum</item>
- <item name="actionModePopupWindowStyle">@style/Widget.Quantum.PopupWindow.ActionMode</item>
- <item name="actionBarWidgetTheme">@null</item>
- <item name="actionBarTheme">@style/ThemeOverlay.Quantum.ActionBar</item>
- <item name="actionBarItemBackground">?attr/selectableItemBackgroundBorderless</item>
-
- <item name="actionModeCutDrawable">@drawable/ic_menu_cut_quantum</item>
- <item name="actionModeCopyDrawable">@drawable/ic_menu_copy_quantum</item>
- <item name="actionModePasteDrawable">@drawable/ic_menu_paste_quantum</item>
- <item name="actionModeSelectAllDrawable">@drawable/ic_menu_selectall_quantum</item>
- <item name="actionModeShareDrawable">@drawable/ic_menu_share_quantum</item>
- <item name="actionModeFindDrawable">@drawable/ic_menu_find_quantum</item>
- <item name="actionModeWebSearchDrawable">@drawable/ic_menu_search_quantum</item>
-
- <item name="dividerVertical">?attr/listDivider</item>
- <item name="dividerHorizontal">?attr/listDivider</item>
- <item name="buttonBarStyle">@style/Widget.Quantum.ButtonBar</item>
- <item name="buttonBarButtonStyle">@style/Widget.Quantum.Button.Borderless</item>
- <item name="segmentedButtonStyle">@style/Widget.Quantum.SegmentedButton</item>
-
- <!-- SearchView attributes -->
- <item name="searchDropdownBackground">?attr/colorBackground</item>
- <item name="searchViewTextField">@drawable/textfield_search_quantum</item>
- <item name="searchViewTextFieldRight">@drawable/textfield_search_quantum</item>
- <item name="searchViewCloseIcon">@android:drawable/ic_clear_quantum</item>
- <item name="searchViewSearchIcon">@android:drawable/ic_search_api_quantum</item>
- <item name="searchViewGoIcon">@android:drawable/ic_go_search_api_quantum</item>
- <item name="searchViewVoiceIcon">@android:drawable/ic_voice_search_api_quantum</item>
- <item name="searchViewEditQuery">@android:drawable/ic_commit_search_api_quantum</item>
-
- <item name="searchDialogTheme">@style/Theme.Quantum.SearchBar</item>
-
- <!-- PreferenceFrameLayout attributes -->
- <item name="preferenceFrameLayoutStyle">@style/Widget.Quantum.PreferenceFrameLayout</item>
-
- <!-- NumberPicker style-->
- <item name="numberPickerStyle">@style/Widget.Quantum.NumberPicker</item>
-
- <!-- CalendarView style-->
- <item name="calendarViewStyle">@style/Widget.Quantum.CalendarView</item>
-
- <!-- TimePicker style -->
- <item name="timePickerStyle">@style/Widget.Quantum.TimePicker</item>
-
- <!-- TimePicker background color -->
- <item name="timePickerHeaderBackgroundColor">?colorBackground</item>
-
- <!-- TimePicker Header time label text appearance -->
- <item name="timePickerHeaderTimeLabelTextAppearance">@style/TextAppearance.Quantum.TimePicker.TimeLabel</item>
-
- <!-- TimePicker Header am pm label text appearance -->
- <item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.Quantum.TimePicker.AmPmLabel</item>
-
- <!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">@style/Theme.Quantum.Dialog.TimePicker</item>
-
- <!-- DatePicker style -->
- <item name="datePickerStyle">@style/Widget.Quantum.DatePicker</item>
-
- <!-- TODO: This belongs in a FastScroll style -->
- <item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_quantum</item>
- <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_dark</item>
- <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_dark</item>
- <item name="fastScrollTrackDrawable">@drawable/fastscroll_track_quantum</item>
- <item name="fastScrollOverlayPosition">atThumb</item>
-
- <!-- Color palette -->
- <item name="colorPrimaryDark">@color/quantum_blue_grey_900</item>
- <item name="colorPrimary">@color/quantum_blue_grey_800</item>
- <item name="colorAccent">@color/quantum_light_blue_A200</item>
-
- <item name="colorControlNormal">?attr/textColorSecondary</item>
- <item name="colorControlActivated">?attr/colorAccent</item>
-
- <item name="colorControlHighlight">@color/ripple_quantum_dark</item>
- <item name="colorButtonNormal">@color/btn_default_quantum_dark</item>
- </style>
-
- <!-- Quantum Paper theme (light version). -->
- <style name="Theme.Quantum.Light" parent="Theme.Light">
- <item name="colorForeground">@color/bright_foreground_quantum_light</item>
- <item name="colorForegroundInverse">@color/bright_foreground_quantum_dark</item>
- <item name="colorBackground">@color/background_quantum_light</item>
- <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_quantum_light</item>
- <item name="disabledAlpha">0.5</item>
- <item name="backgroundDimAmount">0.6</item>
-
- <!-- Text styles -->
- <item name="textAppearance">@style/TextAppearance.Quantum</item>
- <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Inverse</item>
-
- <item name="textColorPrimary">@color/primary_text_quantum_light</item>
- <item name="textColorPrimaryInverse">@color/primary_text_quantum_dark</item>
- <item name="textColorSecondary">@color/secondary_text_quantum_light</item>
- <item name="textColorSecondaryInverse">@color/secondary_text_quantum_dark</item>
- <item name="textColorTertiary">@color/tertiary_text_quantum_light</item>
- <item name="textColorTertiaryInverse">@color/tertiary_text_quantum_dark</item>
- <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_quantum_light</item>
- <item name="textColorPrimaryInverseDisableOnly">@color/primary_text_disable_only_quantum_dark</item>
- <item name="textColorHint">@color/hint_foreground_quantum_light</item>
- <item name="textColorHintInverse">@color/hint_foreground_quantum_dark</item>
- <item name="textColorHighlight">@color/highlighted_text_quantum_light</item>
- <item name="textColorHighlightInverse">@color/highlighted_text_quantum_dark</item>
- <item name="textColorLink">@color/quantum_teal_500</item>
- <item name="textColorLinkInverse">@color/quantum_teal_500</item>
- <item name="textColorSearchUrl">@color/search_url_text_quantum_light</item>
- <item name="textColorAlertDialogListItem">@color/primary_text_quantum_light</item>
-
- <item name="textAppearanceLarge">@style/TextAppearance.Quantum.Large</item>
- <item name="textAppearanceLargeInverse">@style/TextAppearance.Quantum.Large.Inverse</item>
- <item name="textAppearanceMedium">@style/TextAppearance.Quantum.Medium</item>
- <item name="textAppearanceMediumInverse">@style/TextAppearance.Quantum.Medium.Inverse</item>
- <item name="textAppearanceSmall">@style/TextAppearance.Quantum.Small</item>
- <item name="textAppearanceSmallInverse">@style/TextAppearance.Quantum.Small.Inverse</item>
- <item name="textAppearanceSearchResultTitle">@style/TextAppearance.Quantum.SearchResult.Title</item>
- <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.Quantum.SearchResult.Subtitle</item>
-
- <item name="textAppearanceButton">@style/TextAppearance.Quantum.Widget.Button</item>
-
- <item name="editTextColor">?attr/textColorPrimary</item>
- <item name="editTextBackground">@drawable/edit_text_quantum</item>
-
- <item name="candidatesTextStyleSpans">@string/candidates_style</item>
-
- <item name="textCheckMark">@drawable/indicator_check_mark_light</item>
- <item name="textCheckMarkInverse">@drawable/indicator_check_mark_dark</item>
-
- <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Quantum.Widget.PopupMenu.Large</item>
- <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Quantum.Widget.PopupMenu.Small</item>
-
- <!-- Button styles -->
- <item name="buttonStyle">@style/Widget.Quantum.Light.Button</item>
-
- <item name="buttonStyleSmall">@style/Widget.Quantum.Light.Button.Small</item>
- <item name="buttonStyleInset">@style/Widget.Quantum.Light.Button.Inset</item>
-
- <item name="buttonStyleToggle">@style/Widget.Quantum.Light.Button.Toggle</item>
- <item name="switchStyle">@style/Widget.Quantum.Light.CompoundButton.Switch</item>
- <item name="mediaRouteButtonStyle">@style/Widget.Quantum.Light.MediaRouteButton</item>
-
- <item name="selectableItemBackground">@drawable/item_background_quantum</item>
- <item name="selectableItemBackgroundBorderless">@drawable/item_background_borderless_quantum</item>
- <item name="borderlessButtonStyle">@style/Widget.Quantum.Light.Button.Borderless</item>
- <item name="homeAsUpIndicator">@drawable/ic_ab_back_quantum</item>
-
- <!-- List attributes -->
- <item name="listPreferredItemHeight">64dip</item>
- <item name="listPreferredItemHeightSmall">48dip</item>
- <item name="listPreferredItemHeightLarge">80dip</item>
- <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
- <item name="textAppearanceListItem">@style/TextAppearance.Quantum.Subhead</item>
- <item name="textAppearanceListItemSmall">@style/TextAppearance.Quantum.Subhead</item>
- <item name="textAppearanceListItemSecondary">@style/TextAppearance.Quantum.Body1</item>
- <item name="listPreferredItemPaddingLeft">16dip</item>
- <item name="listPreferredItemPaddingRight">16dip</item>
- <item name="listPreferredItemPaddingStart">16dip</item>
- <item name="listPreferredItemPaddingEnd">16dip</item>
-
- <!-- @hide -->
- <item name="searchResultListItemHeight">58dip</item>
- <item name="listDivider">@drawable/list_divider_quantum</item>
- <item name="listSeparatorTextViewStyle">@style/Widget.Quantum.Light.TextView.ListSeparator</item>
-
- <item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum_anim</item>
- <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
-
- <item name="listChoiceBackgroundIndicator">?attr/selectableItemBackground</item>
- <item name="activatedBackgroundIndicator">@drawable/activated_background_quantum</item>
-
- <item name="expandableListPreferredItemPaddingLeft">40dip</item>
- <item name="expandableListPreferredChildPaddingLeft">?attr/expandableListPreferredItemPaddingLeft</item>
-
- <item name="expandableListPreferredItemIndicatorLeft">3dip</item>
- <item name="expandableListPreferredItemIndicatorRight">0dip</item>
- <item name="expandableListPreferredChildIndicatorLeft">?attr/expandableListPreferredItemIndicatorLeft</item>
- <item name="expandableListPreferredChildIndicatorRight">?attr/expandableListPreferredItemIndicatorRight</item>
-
- <item name="listDividerAlertDialog">@drawable/list_divider_quantum</item>
- <item name="findOnPageNextDrawable">@drawable/ic_find_next_quantum</item>
- <item name="findOnPagePreviousDrawable">@drawable/ic_find_previous_quantum</item>
-
- <!-- Gallery attributes -->
- <item name="galleryItemBackground">@drawable/gallery_item_background</item>
-
- <!-- Window attributes -->
- <item name="windowBackground">@color/background_quantum_light</item>
- <item name="windowFrame">@null</item>
- <item name="windowNoTitle">false</item>
- <item name="windowFullscreen">false</item>
- <item name="windowOverscan">false</item>
- <item name="windowIsFloating">false</item>
- <item name="windowContentOverlay">@drawable/ab_solid_shadow_quantum</item>
- <item name="windowShowWallpaper">false</item>
- <item name="windowTitleStyle">@style/WindowTitle.Quantum</item>
- <item name="windowTitleSize">25dip</item>
- <item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.Quantum</item>
- <item name="windowAnimationStyle">@style/Animation.Quantum.Activity</item>
- <item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
- <item name="windowActionBar">true</item>
- <item name="windowActionModeOverlay">false</item>
- <item name="windowDrawsSystemBarBackgrounds">true</item>
- <item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
- <item name="statusBarColor">?attr/colorPrimaryDark</item>
- <item name="navigationBarColor">@color/black</item>
-
- <!-- Dialog attributes -->
- <item name="dialogTheme">@style/Theme.Quantum.Light.Dialog</item>
- <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_quantum</item>
- <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_quantum</item>
- <item name="dialogTitleDecorLayout">@layout/dialog_title_quantum</item>
-
- <!-- AlertDialog attributes -->
- <item name="alertDialogTheme">@style/Theme.Quantum.Light.Dialog.Alert</item>
- <item name="alertDialogStyle">@style/AlertDialog.Quantum.Light</item>
- <item name="alertDialogCenterButtons">false</item>
- <item name="alertDialogIcon">@drawable/ic_dialog_alert_quantum</item>
-
- <!-- Presentation attributes -->
- <item name="presentationTheme">@style/Theme.Quantum.Light.Dialog.Presentation</item>
-
- <!-- Toast attributes -->
- <item name="toastFrameBackground">@drawable/toast_frame</item>
-
- <!-- Panel attributes -->
- <item name="panelBackground">?attr/colorBackground</item>
- <item name="panelFullBackground">@drawable/menu_background_fill_parent_width</item>
- <!-- These three attributes do not seems to be used by the framework. Declared public though -->
- <item name="panelColorBackground">#000</item>
- <item name="panelColorForeground">?attr/textColorPrimary</item>
- <item name="panelTextAppearance">?attr/textAppearance</item>
-
- <item name="panelMenuIsCompact">true</item>
- <item name="panelMenuListWidth">250dip</item>
- <item name="panelMenuListTheme">@style/Theme.Quantum.Light.CompactMenu</item>
-
- <!-- Scrollbar attributes -->
- <item name="scrollbarFadeDuration">250</item>
- <item name="scrollbarDefaultDelayBeforeFade">300</item>
- <item name="scrollbarSize">10dip</item>
- <item name="scrollbarThumbHorizontal">@drawable/scrollbar_handle_quantum</item>
- <item name="scrollbarThumbVertical">@drawable/scrollbar_handle_quantum</item>
- <item name="scrollbarTrackHorizontal">@null</item>
- <item name="scrollbarTrackVertical">@null</item>
-
- <!-- Text selection handle attributes -->
- <item name="textSelectHandleLeft">@drawable/text_select_handle_left_quantum</item>
- <item name="textSelectHandleRight">@drawable/text_select_handle_right_quantum</item>
- <item name="textSelectHandle">@drawable/text_select_handle_middle_quantum</item>
- <item name="textSelectHandleWindowStyle">@style/Widget.Quantum.TextSelectHandle</item>
- <item name="textSuggestionsWindowStyle">@style/Widget.Quantum.Light.TextSuggestionsPopupWindow</item>
- <item name="textCursorDrawable">@drawable/text_cursor_quantum</item>
-
- <!-- Widget styles -->
- <item name="absListViewStyle">@style/Widget.Quantum.Light.AbsListView</item>
- <item name="autoCompleteTextViewStyle">@style/Widget.Quantum.Light.AutoCompleteTextView</item>
- <item name="checkboxStyle">@style/Widget.Quantum.Light.CompoundButton.CheckBox</item>
- <item name="checkedTextViewStyle">@style/Widget.Quantum.Light.CheckedTextView</item>
- <item name="dropDownListViewStyle">@style/Widget.Quantum.ListView.DropDown</item>
- <item name="editTextStyle">@style/Widget.Quantum.Light.EditText</item>
- <item name="expandableListViewStyle">@style/Widget.Quantum.Light.ExpandableListView</item>
- <item name="expandableListViewWhiteStyle">@style/Widget.Quantum.Light.ExpandableListView.White</item>
- <item name="fastScrollStyle">@style/Widget.Quantum.Light.FastScroll</item>
- <item name="galleryStyle">@style/Widget.Quantum.Light.Gallery</item>
- <item name="gestureOverlayViewStyle">@style/Widget.Quantum.Light.GestureOverlayView</item>
- <item name="gridViewStyle">@style/Widget.Quantum.Light.GridView</item>
- <item name="imageButtonStyle">@style/Widget.Quantum.Light.ImageButton</item>
- <item name="imageWellStyle">@style/Widget.Quantum.Light.ImageWell</item>
- <item name="listViewStyle">@style/Widget.Quantum.Light.ListView</item>
- <item name="listViewWhiteStyle">@style/Widget.Quantum.Light.ListView.White</item>
- <item name="popupWindowStyle">@style/Widget.Quantum.Light.PopupWindow</item>
- <item name="progressBarStyle">@style/Widget.Quantum.Light.ProgressBar</item>
- <item name="progressBarStyleHorizontal">@style/Widget.Quantum.Light.ProgressBar.Horizontal</item>
- <item name="progressBarStyleSmall">@style/Widget.Quantum.Light.ProgressBar.Small</item>
- <item name="progressBarStyleSmallTitle">@style/Widget.Quantum.Light.ProgressBar.Small.Title</item>
- <item name="progressBarStyleLarge">@style/Widget.Quantum.Light.ProgressBar.Large</item>
- <item name="progressBarStyleInverse">@style/Widget.Quantum.Light.ProgressBar.Inverse</item>
- <item name="progressBarStyleSmallInverse">@style/Widget.Quantum.Light.ProgressBar.Small.Inverse</item>
- <item name="progressBarStyleLargeInverse">@style/Widget.Quantum.Light.ProgressBar.Large.Inverse</item>
- <item name="seekBarStyle">@style/Widget.Quantum.Light.SeekBar</item>
- <item name="ratingBarStyle">@style/Widget.Quantum.Light.RatingBar</item>
- <item name="ratingBarStyleIndicator">@style/Widget.Quantum.Light.RatingBar.Indicator</item>
- <item name="ratingBarStyleSmall">@style/Widget.Quantum.Light.RatingBar.Small</item>
- <item name="radioButtonStyle">@style/Widget.Quantum.Light.CompoundButton.RadioButton</item>
- <item name="scrollViewStyle">@style/Widget.Quantum.Light.ScrollView</item>
- <item name="horizontalScrollViewStyle">@style/Widget.Quantum.Light.HorizontalScrollView</item>
- <item name="spinnerStyle">?attr/dropDownSpinnerStyle</item>
- <item name="dropDownSpinnerStyle">@style/Widget.Quantum.Light.Spinner.DropDown</item>
- <item name="starStyle">@style/Widget.Quantum.Light.CompoundButton.Star</item>
- <item name="tabWidgetStyle">@style/Widget.Quantum.Light.TabWidget</item>
- <item name="textViewStyle">@style/Widget.Quantum.Light.TextView</item>
- <item name="errorMessageBackground">@drawable/popup_inline_error_holo_light</item>
- <item name="errorMessageAboveBackground">@drawable/popup_inline_error_above_holo_light</item>
- <item name="webTextViewStyle">@style/Widget.Quantum.Light.WebTextView</item>
- <item name="webViewStyle">@style/Widget.Quantum.Light.WebView</item>
- <item name="dropDownItemStyle">@style/Widget.Quantum.Light.DropDownItem</item>
- <item name="spinnerDropDownItemStyle">@style/Widget.Quantum.Light.DropDownItem.Spinner</item>
- <item name="spinnerItemStyle">@style/Widget.Quantum.TextView.SpinnerItem</item>
- <item name="dropDownHintAppearance">@style/TextAppearance.Quantum.Widget.DropDownHint</item>
- <item name="keyboardViewStyle">@style/Widget.Quantum.KeyboardView</item>
- <item name="quickContactBadgeStyleWindowSmall">@style/Widget.Quantum.QuickContactBadge.WindowSmall</item>
- <item name="quickContactBadgeStyleWindowMedium">@style/Widget.Quantum.QuickContactBadge.WindowMedium</item>
- <item name="quickContactBadgeStyleWindowLarge">@style/Widget.Quantum.QuickContactBadge.WindowLarge</item>
- <item name="quickContactBadgeStyleSmallWindowSmall">@style/Widget.Quantum.QuickContactBadgeSmall.WindowSmall</item>
- <item name="quickContactBadgeStyleSmallWindowMedium">@style/Widget.Quantum.QuickContactBadgeSmall.WindowMedium</item>
- <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Quantum.QuickContactBadgeSmall.WindowLarge</item>
- <item name="listPopupWindowStyle">@style/Widget.Quantum.Light.ListPopupWindow</item>
- <item name="popupMenuStyle">@style/Widget.Quantum.Light.PopupMenu</item>
- <item name="stackViewStyle">@style/Widget.Quantum.Light.StackView</item>
- <item name="activityChooserViewStyle">@style/Widget.Quantum.Light.ActivityChooserView</item>
-
- <!-- Preference styles -->
- <item name="preferenceScreenStyle">@style/Preference.Quantum.PreferenceScreen</item>
- <item name="preferenceFragmentStyle">@style/PreferenceFragment.Quantum</item>
- <item name="preferenceFragmentPaddingSide">0dip</item>
- <item name="preferenceCategoryStyle">@style/Preference.Quantum.Category</item>
- <item name="preferenceStyle">@style/Preference.Quantum</item>
- <item name="preferenceInformationStyle">@style/Preference.Quantum.Information</item>
- <item name="checkBoxPreferenceStyle">@style/Preference.Quantum.CheckBoxPreference</item>
- <item name="switchPreferenceStyle">@style/Preference.Quantum.SwitchPreference</item>
- <item name="yesNoPreferenceStyle">@style/Preference.Quantum.DialogPreference.YesNoPreference</item>
- <item name="dialogPreferenceStyle">@style/Preference.Quantum.DialogPreference</item>
- <item name="editTextPreferenceStyle">@style/Preference.Quantum.DialogPreference.EditTextPreference</item>
- <item name="ringtonePreferenceStyle">@style/Preference.Quantum.RingtonePreference</item>
- <item name="preferenceLayoutChild">@layout/preference_child_quantum</item>
- <item name="detailsElementBackground">?attr/colorBackground</item>
-
- <!-- PreferenceFrameLayout attributes -->
- <item name="preferenceFrameLayoutStyle">@style/Widget.Quantum.PreferenceFrameLayout</item>
-
- <!-- Search widget styles -->
- <item name="searchWidgetCorpusItemBackground">@color/search_widget_corpus_item_background</item>
-
- <!-- Action bar styles -->
- <item name="actionDropDownStyle">@style/Widget.Quantum.Light.Spinner.DropDown.ActionBar</item>
- <item name="actionButtonStyle">@style/Widget.Quantum.Light.ActionButton</item>
- <item name="actionOverflowButtonStyle">@style/Widget.Quantum.Light.ActionButton.Overflow</item>
- <item name="actionOverflowMenuStyle">@android:style/Widget.Quantum.Light.PopupMenu.Overflow</item>
- <item name="actionModeBackground">@drawable/cab_background_top_holo_light</item>
- <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
- <item name="actionModeCloseDrawable">@drawable/ic_cab_done_quantum</item>
- <item name="actionBarTabStyle">@style/Widget.Quantum.Light.ActionBar.TabView</item>
- <item name="actionBarTabBarStyle">@style/Widget.Quantum.Light.ActionBar.TabBar</item>
- <item name="actionBarTabTextStyle">@style/Widget.Quantum.Light.ActionBar.TabText</item>
- <item name="actionModeStyle">@style/Widget.Quantum.Light.ActionMode</item>
- <item name="actionModeCloseButtonStyle">@style/Widget.Quantum.Light.ActionButton.CloseMode</item>
- <item name="actionBarStyle">@style/Widget.Quantum.Light.ActionBar.Solid</item>
- <item name="actionBarSize">@dimen/action_bar_default_height_quantum</item>
- <item name="actionModePopupWindowStyle">@style/Widget.Quantum.Light.PopupWindow.ActionMode</item>
- <item name="actionBarWidgetTheme">@null</item>
- <item name="actionBarTheme">@style/ThemeOverlay.Quantum.ActionBar</item>
- <item name="actionBarItemBackground">?attr/selectableItemBackgroundBorderless</item>
-
- <item name="actionModeCutDrawable">@drawable/ic_menu_cut_quantum</item>
- <item name="actionModeCopyDrawable">@drawable/ic_menu_copy_quantum</item>
- <item name="actionModePasteDrawable">@drawable/ic_menu_paste_quantum</item>
- <item name="actionModeSelectAllDrawable">@drawable/ic_menu_selectall_quantum</item>
- <item name="actionModeShareDrawable">@drawable/ic_menu_share_quantum</item>
- <item name="actionModeFindDrawable">@drawable/ic_menu_find_quantum</item>
- <item name="actionModeWebSearchDrawable">@drawable/ic_menu_search_quantum</item>
-
- <item name="dividerVertical">?attr/listDivider</item>
- <item name="dividerHorizontal">?attr/listDivider</item>
- <item name="buttonBarStyle">@style/Widget.Quantum.Light.ButtonBar</item>
- <item name="buttonBarButtonStyle">@style/Widget.Quantum.Light.Button.Borderless</item>
- <item name="segmentedButtonStyle">@style/Widget.Quantum.Light.SegmentedButton</item>
-
- <!-- SearchView attributes -->
- <item name="searchDropdownBackground">?attr/colorBackground</item>
- <item name="searchViewTextField">@drawable/textfield_search_quantum</item>
- <item name="searchViewTextFieldRight">@drawable/textfield_search_quantum</item>
- <item name="searchViewCloseIcon">@android:drawable/ic_clear_quantum</item>
- <item name="searchViewSearchIcon">@android:drawable/ic_search_api_quantum</item>
- <item name="searchViewGoIcon">@android:drawable/ic_go_search_api_quantum</item>
- <item name="searchViewVoiceIcon">@android:drawable/ic_voice_search_api_quantum</item>
- <item name="searchViewEditQuery">@android:drawable/ic_commit_search_api_quantum</item>
-
- <item name="searchDialogTheme">@style/Theme.Quantum.Light.SearchBar</item>
-
- <!-- NumberPicker style-->
- <item name="numberPickerStyle">@style/Widget.Quantum.Light.NumberPicker</item>
-
- <!-- CalendarView style-->
- <item name="calendarViewStyle">@style/Widget.Quantum.Light.CalendarView</item>
-
- <!-- TimePicker style -->
- <item name="timePickerStyle">@style/Widget.Quantum.Light.TimePicker</item>
-
- <!-- TimePicker Header background color -->
- <item name="timePickerHeaderBackgroundColor">?attr/colorBackground</item>
-
- <!-- TimePicker Header time label text appearance -->
- <item name="timePickerHeaderTimeLabelTextAppearance">@style/TextAppearance.Quantum.TimePicker.TimeLabel</item>
-
- <!-- TimePicker Header am pm label text appearance -->
- <item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.Quantum.TimePicker.AmPmLabel</item>
-
- <!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">@style/Theme.Quantum.Light.Dialog.TimePicker</item>
-
- <!-- DatePicker style -->
- <item name="datePickerStyle">@style/Widget.Quantum.Light.DatePicker</item>
-
- <item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_quantum</item>
- <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_light</item>
- <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_light</item>
- <item name="fastScrollTrackDrawable">@drawable/fastscroll_track_quantum</item>
- <item name="fastScrollOverlayPosition">atThumb</item>
-
- <!-- Color palette -->
- <item name="colorPrimaryDark">@color/quantum_blue_grey_600</item>
- <item name="colorPrimary">@color/quantum_blue_grey_400</item>
- <item name="colorAccent">@color/quantum_light_blue_A200</item>
-
- <item name="colorControlNormal">?attr/textColorSecondary</item>
- <item name="colorControlActivated">?attr/colorAccent</item>
-
- <item name="colorControlHighlight">@color/ripple_quantum_light</item>
- <item name="colorButtonNormal">@color/btn_default_quantum_light</item>
- </style>
-
- <!-- Variant of the quantum (light) theme that has a solid (opaque) action bar
- with an inverse color profile. The dark action bar sharply stands out against
- the light content. -->
- <style name="Theme.Quantum.Light.DarkActionBar">
- <item name="actionBarWidgetTheme">@null</item>
- <item name="actionBarTheme">@style/ThemeOverlay.Quantum.Dark.ActionBar</item>
- </style>
-
- <style name="ThemeOverlay" />
- <style name="ThemeOverlay.Quantum" />
-
- <!-- Theme overlay that replaces colors with their light versions but preserves
- the value of colorAccent, colorPrimary and its variants. -->
- <style name="ThemeOverlay.Quantum.Light">
- <item name="colorForeground">@color/bright_foreground_quantum_light</item>
- <item name="colorForegroundInverse">@color/bright_foreground_quantum_dark</item>
- <item name="colorBackground">@color/background_quantum_light</item>
- <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_quantum_light</item>
-
- <item name="textColorPrimary">@color/primary_text_quantum_light</item>
- <item name="textColorPrimaryInverse">@color/primary_text_quantum_dark</item>
- <item name="textColorSecondary">@color/secondary_text_quantum_light</item>
- <item name="textColorSecondaryInverse">@color/secondary_text_quantum_dark</item>
- <item name="textColorTertiary">@color/tertiary_text_quantum_light</item>
- <item name="textColorTertiaryInverse">@color/tertiary_text_quantum_dark</item>
- <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_quantum_light</item>
- <item name="textColorPrimaryInverseDisableOnly">@color/primary_text_disable_only_quantum_dark</item>
- <item name="textColorHint">@color/hint_foreground_quantum_light</item>
- <item name="textColorHintInverse">@color/hint_foreground_quantum_dark</item>
- <item name="textColorHighlight">@color/highlighted_text_quantum_light</item>
- <item name="textColorHighlightInverse">@color/highlighted_text_quantum_dark</item>
- <item name="textColorLink">@color/quantum_teal_500</item>
- <item name="textColorLinkInverse">@color/quantum_teal_500</item>
- <item name="textColorSearchUrl">@color/search_url_text_quantum_light</item>
- <item name="textColorAlertDialogListItem">@color/primary_text_quantum_light</item>
-
- <item name="textCheckMark">@drawable/indicator_check_mark_light</item>
- <item name="textCheckMarkInverse">@drawable/indicator_check_mark_dark</item>
-
- <item name="windowBackground">@color/background_quantum_light</item>
-
- <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_light</item>
- <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_light</item>
-
- <item name="colorControlHighlight">@color/ripple_quantum_light</item>
- <item name="colorButtonNormal">@color/btn_default_quantum_light</item>
- </style>
-
- <!-- Theme overlay that replaces colors with their dark versions but preserves
- the value of colorAccent, colorPrimary and its variants. -->
- <style name="ThemeOverlay.Quantum.Dark">
- <item name="colorForeground">@color/bright_foreground_quantum_dark</item>
- <item name="colorForegroundInverse">@color/bright_foreground_quantum_light</item>
- <item name="colorBackground">@color/background_quantum_dark</item>
- <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_quantum_dark</item>
-
- <item name="textColorPrimary">@color/primary_text_quantum_dark</item>
- <item name="textColorPrimaryInverse">@color/primary_text_quantum_light</item>
- <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_quantum_dark</item>
- <item name="textColorSecondary">@color/secondary_text_quantum_dark</item>
- <item name="textColorSecondaryInverse">@color/secondary_text_quantum_light</item>
- <item name="textColorTertiary">@color/tertiary_text_quantum_dark</item>
- <item name="textColorTertiaryInverse">@color/tertiary_text_quantum_light</item>
- <item name="textColorHint">@color/hint_foreground_quantum_dark</item>
- <item name="textColorHintInverse">@color/hint_foreground_quantum_light</item>
- <item name="textColorHighlight">@color/highlighted_text_quantum_dark</item>
- <item name="textColorHighlightInverse">@color/highlighted_text_quantum_light</item>
- <item name="textColorLink">@color/quantum_teal_500</item>
- <item name="textColorLinkInverse">@color/quantum_teal_500</item>
- <item name="textColorSearchUrl">@color/search_url_text_quantum_dark</item>
- <item name="textColorAlertDialogListItem">@color/primary_text_quantum_dark</item>
-
- <item name="textCheckMark">@drawable/indicator_check_mark_dark</item>
- <item name="textCheckMarkInverse">@drawable/indicator_check_mark_light</item>
-
- <item name="windowBackground">@color/background_quantum_dark</item>
-
- <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_dark</item>
- <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_dark</item>
-
- <item name="colorControlHighlight">@color/ripple_quantum_dark</item>
- <item name="colorButtonNormal">@color/btn_default_quantum_dark</item>
- </style>
-
- <!-- Theme overlay that replaces the normal control color, which by default is the same as the
- secondary text color, with the primary text color. -->
- <style name="ThemeOverlay.Quantum.ActionBar">
- <item name="colorControlNormal">?attr/textColorPrimary</item>
- </style>
-
- <!-- Theme overlay that replaces colors with their dark versions and replaces the normal
- control color, which by default is the same as the secondary text color, with the primary
- text color. -->
- <style name="ThemeOverlay.Quantum.Dark.ActionBar">
- <item name="colorControlNormal">?attr/textColorPrimary</item>
- </style>
-
- <!-- Variant of the quantum (dark) theme with no action bar. -->
- <style name="Theme.Quantum.NoActionBar">
- <item name="windowActionBar">false</item>
- <item name="windowNoTitle">true</item>
- </style>
-
- <!-- Variant of the quantum (dark) theme that has no title bar and fills
- the entire screen. This theme
- sets {@link android.R.attr#windowFullscreen} to true. -->
- <style name="Theme.Quantum.NoActionBar.Fullscreen">
- <item name="windowFullscreen">true</item>
- <item name="windowContentOverlay">@null</item>
- </style>
-
- <!-- Variant of the quantum (dark) theme that has no title bar and fills
- the entire screen and extends into the display overscan region. This theme
- sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
- to true. -->
- <style name="Theme.Quantum.NoActionBar.Overscan">
- <item name="windowFullscreen">true</item>
- <item name="windowOverscan">true</item>
- <item name="windowContentOverlay">@null</item>
- </style>
-
- <!-- Variant of the quantum (dark) theme that has no title bar and translucent
- system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
- {@link android.R.attr#windowTranslucentNavigation} to true. -->
- <style name="Theme.Quantum.NoActionBar.TranslucentDecor">
- <item name="windowTranslucentStatus">true</item>
- <item name="windowTranslucentNavigation">true</item>
- <item name="windowContentOverlay">@null</item>
- </style>
-
- <!-- Variant of the quantum (light) theme with no action bar. -->
- <style name="Theme.Quantum.Light.NoActionBar">
- <item name="windowActionBar">false</item>
- <item name="windowNoTitle">true</item>
- </style>
-
- <!-- Variant of the quantum (light) theme that has no title bar and fills
- the entire screen. This theme
- sets {@link android.R.attr#windowFullscreen} to true. -->
- <style name="Theme.Quantum.Light.NoActionBar.Fullscreen">
- <item name="windowFullscreen">true</item>
- <item name="windowContentOverlay">@null</item>
- </style>
-
- <!-- Variant of the quantum (light) theme that has no title bar and fills
- the entire screen and extends into the display overscan region. This theme
- sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
- to true. -->
- <style name="Theme.Quantum.Light.NoActionBar.Overscan">
- <item name="windowFullscreen">true</item>
- <item name="windowOverscan">true</item>
- <item name="windowContentOverlay">@null</item>
- </style>
-
- <!-- Variant of the quantum (light) theme that has no title bar and translucent
- system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
- {@link android.R.attr#windowTranslucentNavigation} to true. -->
- <style name="Theme.Quantum.Light.NoActionBar.TranslucentDecor">
- <item name="windowTranslucentStatus">true</item>
- <item name="windowTranslucentNavigation">true</item>
- <item name="windowContentOverlay">@null</item>
- </style>
-
- <!-- Default quantum dark theme for panel windows. This removes all extraneous
- window decorations, so you basically have an empty rectangle in which
- to place your content. It makes the window floating, with a transparent
- background, and turns off dimming behind the window. -->
- <style name="Theme.Quantum.Panel">
- <item name="windowBackground">@color/transparent</item>
- <item name="colorBackgroundCacheHint">@null</item>
- <item name="windowFrame">@null</item>
- <item name="windowContentOverlay">@null</item>
- <item name="windowAnimationStyle">@null</item>
- <item name="windowIsFloating">true</item>
- <item name="backgroundDimEnabled">false</item>
- <item name="windowIsTranslucent">true</item>
- <item name="windowNoTitle">true</item>
- </style>
-
- <!-- Default quantum light theme for panel windows. This removes all extraneous
- window decorations, so you basically have an empty rectangle in which
- to place your content. It makes the window floating, with a transparent
- background, and turns off dimming behind the window. -->
- <style name="Theme.Quantum.Light.Panel">
- <item name="windowBackground">@color/transparent</item>
- <item name="colorBackgroundCacheHint">@null</item>
- <item name="windowFrame">@null</item>
- <item name="windowContentOverlay">@null</item>
- <item name="windowAnimationStyle">@null</item>
- <item name="windowIsFloating">true</item>
- <item name="backgroundDimEnabled">false</item>
- <item name="windowIsTranslucent">true</item>
- <item name="windowNoTitle">true</item>
- </style>
-
- <!-- Quantum theme for an activity that is to be used for voice interaction.
- This gives the activity a floating dialog style, to incorporate with the
- system voice experience. -->
- <style name="Theme.Quantum.Voice" parent="@style/Theme.Quantum.Dialog">
- <item name="windowAnimationStyle">@style/Animation.VoiceActivity</item>
- <item name="backgroundDimEnabled">false</item>
- </style>
-
- <!-- Quantum light theme for an activity that is to be used for voice interaction.
- This gives the activity a floating dialog style, to incorporate with the
- system voice experience. -->
- <style name="Theme.Quantum.Light.Voice" parent="@style/Theme.Quantum.Light.Dialog">
- <item name="windowAnimationStyle">@style/Animation.VoiceActivity</item>
- <item name="backgroundDimEnabled">false</item>
- </style>
-
- <!-- Default theme for quantum style input methods, which is used by the
- {@link android.inputmethodservice.InputMethodService} class.
- this inherits from Theme.Panel, but sets up IME appropriate animations
- and a few custom attributes. -->
- <style name="Theme.Quantum.InputMethod" parent="Theme.Quantum.Light.Panel">
- <item name="windowAnimationStyle">@style/Animation.InputMethod</item>
- <item name="imeFullscreenBackground">@drawable/screen_background_selector_light</item>
- <item name="imeExtractEnterAnimation">@anim/input_method_extract_enter</item>
- <item name="imeExtractExitAnimation">@anim/input_method_extract_exit</item>
- </style>
-
- <!-- Default theme for quantum style voice interaction, which is used by the
- {@link android.service.voice.VoiceInteractionSession} class.
- this inherits from Theme.Panel, but sets up appropriate animations
- and a few custom attributes. -->
- <style name="Theme.Quantum.VoiceInteractionSession" parent="Theme.Quantum.Light.Panel">
- <item name="windowAnimationStyle">@style/Animation.VoiceInteractionSession</item>
- </style>
-
- <!-- Theme for the search input bar. -->
-
- <style name="Theme.Quantum.SearchBar" parent="Theme.Quantum.Panel">
- <item name="actionModeBackground">@drawable/cab_background_top_holo_dark</item>
- <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
- </style>
-
- <style name="Theme.Quantum.Light.SearchBar" parent="Theme.Quantum.Light.Panel">
- <item name="actionModeBackground">@drawable/cab_background_top_holo_light</item>
- <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
- </style>
-
- <!-- Menu Themes -->
- <eat-comment />
-
- <style name="Theme.Quantum.CompactMenu">
- <!-- Menu/item attributes -->
- <item name="itemTextAppearance">?attr/textAppearanceMedium</item>
- <item name="listViewStyle">@style/Widget.Quantum.ListView</item>
- <item name="windowAnimationStyle">@style/Animation.DropDownUp</item>
- <item name="background">@null</item>
- </style>
-
- <style name="Theme.Quantum.Light.CompactMenu">
- <!-- Menu/item attributes -->
- <item name="itemTextAppearance">?attr/textAppearanceMedium</item>
- <item name="listViewStyle">@style/Widget.Quantum.Light.ListView</item>
- <item name="windowAnimationStyle">@style/Animation.DropDownUp</item>
- <item name="background">@null</item>
- </style>
-
- <!-- Dialog themes for Quantum -->
- <eat-comment />
-
- <!-- Quantum theme for dialog windows and activities, which is used by the
- {@link android.app.Dialog} class. This changes the window to be
- floating (not fill the entire screen), and puts a frame around its
- contents. You can set this theme on an activity if you would like to
- make an activity that looks like a Dialog. -->
- <style name="Theme.Quantum.Dialog">
- <item name="windowFrame">@null</item>
- <item name="windowTitleStyle">@style/DialogWindowTitle.Quantum</item>
- <item name="windowBackground">@drawable/dialog_background_quantum</item>
- <item name="windowIsFloating">true</item>
- <item name="windowContentOverlay">@null</item>
- <item name="windowAnimationStyle">@style/Animation.Quantum.Dialog</item>
- <item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
- <item name="windowActionBar">false</item>
- <item name="windowActionModeOverlay">true</item>
- <item name="windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
-
- <item name="colorBackgroundCacheHint">@null</item>
-
- <item name="buttonBarStyle">@style/Widget.Quantum.ButtonBar.AlertDialog</item>
- <item name="borderlessButtonStyle">@style/Widget.Quantum.Button.Borderless</item>
-
- <item name="textAppearance">@style/TextAppearance.Quantum</item>
- <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Inverse</item>
-
- <item name="listPreferredItemPaddingLeft">16dip</item>
- <item name="listPreferredItemPaddingRight">16dip</item>
- <item name="listPreferredItemPaddingStart">16dip</item>
- <item name="listPreferredItemPaddingEnd">16dip</item>
-
- <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
- </style>
-
- <!-- Variant of Theme.Quantum.Dialog that has a nice minimum width for
- a regular dialog. -->
- <style name="Theme.Quantum.Dialog.MinWidth">
- <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
- <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
- </style>
-
- <!-- Variant of Theme.Quantum.Dialog that does not include a title bar. -->
- <style name="Theme.Quantum.Dialog.NoActionBar">
- <item name="windowActionBar">false</item>
- <item name="windowNoTitle">true</item>
- </style>
-
- <!-- Variant of Theme.Quantum.Dialog.NoActionBar that has a nice minimum width for
- a regular dialog. -->
- <style name="Theme.Quantum.Dialog.NoActionBar.MinWidth">
- <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
- <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
- </style>
-
- <!-- Variant of Theme.Quantum.Dialog that has a fixed size. -->
- <style name="Theme.Quantum.Dialog.FixedSize">
- <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
- <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
- <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
- <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
- </style>
-
- <!-- Variant of Theme.Quantum.Dialog.NoActionBar that has a fixed size. -->
- <style name="Theme.Quantum.Dialog.NoActionBar.FixedSize">
- <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
- <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
- <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
- <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
- </style>
-
- <!-- Variant of Theme.Quantum.Dialog that does not include a frame (or background).
- The view hierarchy of the dialog is responsible for drawing all of
- its pixels. -->
- <style name="Theme.Quantum.Dialog.NoFrame">
- <item name="windowBackground">@color/transparent</item>
- <item name="windowAnimationStyle">@null</item>
- <item name="backgroundDimEnabled">false</item>
- <item name="windowIsTranslucent">true</item>
- <item name="windowNoTitle">true</item>
- <item name="windowCloseOnTouchOutside">false</item>
- </style>
-
- <!-- Quantum theme for alert dialog windows, which is used by the
- {@link android.app.AlertDialog} class. This is basically a dialog
- but sets the background to empty so it can do two-tone backgrounds.
- For applications targeting Honeycomb or newer, this is the default
- AlertDialog theme. -->
- <style name="Theme.Quantum.Dialog.Alert">
- <item name="windowBackground">@color/transparent</item>
- <item name="windowTitleStyle">@style/DialogWindowTitle.Quantum</item>
- <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
- <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
- </style>
-
- <!-- Quantum theme for the TimePicker dialog windows, which is used by the
- {@link android.app.TimePickerDialog} class. -->
- <style name="Theme.Quantum.Dialog.TimePicker">
- <item name="windowBackground">@color/transparent</item>
- <item name="windowTitleStyle">@style/DialogWindowTitle.Quantum</item>
- <item name="windowContentOverlay">@null</item>
- </style>
-
- <!-- Theme for a window that will be displayed either full-screen on
- smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
- <style name="Theme.Quantum.DialogWhenLarge" parent="@style/Theme.Quantum">
- </style>
-
- <!-- Theme for a window without a title bar that will be displayed either
- full-screen on smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
- <style name="Theme.Quantum.DialogWhenLarge.NoActionBar" parent="@style/Theme.Quantum.NoActionBar">
- </style>
-
- <!-- Theme for a presentation window on a secondary display. -->
- <style name="Theme.Quantum.Dialog.Presentation" parent="@style/Theme.Quantum.NoActionBar.Fullscreen">
- </style>
-
- <!-- Light quantum dialog themes -->
-
- <!-- Quantum light theme for dialog windows and activities, which is used by the
- {@link android.app.Dialog} class. This changes the window to be
- floating (not fill the entire screen), and puts a frame around its
- contents. You can set this theme on an activity if you would like to
- make an activity that looks like a Dialog. -->
- <style name="Theme.Quantum.Light.Dialog">
- <item name="windowFrame">@null</item>
- <item name="windowTitleStyle">@style/DialogWindowTitle.Quantum.Light</item>
- <item name="windowBackground">?attr/colorBackground</item>
- <item name="windowIsFloating">true</item>
- <item name="windowContentOverlay">@null</item>
- <item name="windowAnimationStyle">@style/Animation.Quantum.Dialog</item>
- <item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
- <item name="windowActionBar">false</item>
- <item name="windowActionModeOverlay">true</item>
- <item name="windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
-
- <item name="colorBackgroundCacheHint">@null</item>
-
- <item name="buttonBarStyle">@style/Widget.Quantum.Light.ButtonBar.AlertDialog</item>
- <item name="borderlessButtonStyle">@style/Widget.Quantum.Light.Button.Borderless</item>
-
- <item name="textAppearance">@style/TextAppearance.Quantum</item>
- <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Inverse</item>
-
- <item name="listPreferredItemPaddingLeft">16dip</item>
- <item name="listPreferredItemPaddingRight">16dip</item>
- <item name="listPreferredItemPaddingStart">16dip</item>
- <item name="listPreferredItemPaddingEnd">16dip</item>
-
- <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
- </style>
-
- <!-- Variant of Theme.Quantum.Light.Dialog that has a nice minimum width for
- a regular dialog. -->
- <style name="Theme.Quantum.Light.Dialog.MinWidth">
- <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
- <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
- </style>
-
- <!-- Variant of Theme.Quantum.Light.Dialog that does not include a title bar. -->
- <style name="Theme.Quantum.Light.Dialog.NoActionBar">
- <item name="windowActionBar">false</item>
- <item name="windowNoTitle">true</item>
- </style>
-
- <!-- Variant of Theme.Quantum.Light.Dialog.NoActionBar that has a nice minimum width for
- a regular dialog. -->
- <style name="Theme.Quantum.Light.Dialog.NoActionBar.MinWidth">
- <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
- <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
- </style>
-
- <!-- Variant of Theme.Quantum.Light.Dialog that has a fixed size. -->
- <style name="Theme.Quantum.Light.Dialog.FixedSize">
- <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
- <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
- <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
- <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
- </style>
-
- <!-- Variant of Theme.Quantum.Light.Dialog.NoActionBar that has a fixed size. -->
- <style name="Theme.Quantum.Light.Dialog.NoActionBar.FixedSize">
- <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
- <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
- <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
- <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
- </style>
-
- <!-- Theme for a window that will be displayed either full-screen on
- smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
- <style name="Theme.Quantum.Light.DialogWhenLarge" parent="@style/Theme.Quantum.Light">
- </style>
-
- <!-- Theme for a window without an action bar that will be displayed either full-screen
- on smaller screens (small, normal) or as a dialog on larger screens
- (large, xlarge). -->
- <style name="Theme.Quantum.Light.DialogWhenLarge.NoActionBar"
- parent="@style/Theme.Quantum.Light.NoActionBar">
- </style>
-
- <!-- Quantum light theme for alert dialog windows, which is used by the
- {@link android.app.AlertDialog} class. This is basically a dialog
- but sets the background to empty so it can do two-tone backgrounds.
- For applications targeting Honeycomb or newer, this is the default
- AlertDialog theme. -->
- <style name="Theme.Quantum.Light.Dialog.Alert">
- <item name="windowBackground">@color/transparent</item>
- <item name="windowTitleStyle">@style/DialogWindowTitle.Quantum.Light</item>
- <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
- <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
- </style>
-
- <!-- Quantum Light theme for the TimePicker dialog windows, which is used by the
- {@link android.app.TimePickerDialog} class. -->
- <style name="Theme.Quantum.Light.Dialog.TimePicker">
- <item name="windowBackground">@color/transparent</item>
- <item name="windowTitleStyle">@style/DialogWindowTitle.Quantum.Light</item>
- </style>
-
- <!-- Theme for a presentation window on a secondary display. -->
- <style name="Theme.Quantum.Light.Dialog.Presentation" parent="@style/Theme.Quantum.Light.NoActionBar.Fullscreen" >
- </style>
-
- <!-- Default quantum (dark) for windows that want to have the user's selected
- wallpaper appear behind them. -->
- <style name="Theme.Quantum.Wallpaper">
- <item name="windowBackground">@color/transparent</item>
- <item name="colorBackgroundCacheHint">@null</item>
- <item name="windowShowWallpaper">true</item>
- </style>
-
- <!--Default quantum (dark) for windows that want to have the user's selected
- wallpaper appear behind them and without an action bar. -->
- <style name="Theme.Quantum.Wallpaper.NoTitleBar">
- <item name="windowNoTitle">true</item>
- </style>
-
-</resources>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index db125e6..116a31e 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -336,7 +336,7 @@
if (!InetAddress.isNumeric(dnsAddr)) {
throw new SAXException();
}
- mLinkProperties.addDns(InetAddress.getByName(dnsAddr));
+ mLinkProperties.addDnsServer(InetAddress.getByName(dnsAddr));
} catch (UnknownHostException e) {
throw new SAXException();
}
@@ -348,7 +348,7 @@
if (!InetAddress.isNumeric(dnsAddr)) {
throw new SAXException();
}
- mLinkProperties.addDns(InetAddress.getByName(dnsAddr));
+ mLinkProperties.addDnsServer(InetAddress.getByName(dnsAddr));
} catch (UnknownHostException e) {
throw new SAXException();
}
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 07a6a10..7251e7c 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -29,6 +29,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageParser.PackageParserException;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.net.Uri;
@@ -60,7 +61,6 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -303,14 +303,13 @@
return Uri.fromFile(outFile);
}
- private PackageParser.Package parsePackage(Uri packageURI) {
+ private PackageParser.Package parsePackage(Uri packageURI) throws PackageParserException {
final String archiveFilePath = packageURI.getPath();
PackageParser packageParser = new PackageParser(archiveFilePath);
File sourceFile = new File(archiveFilePath);
DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
- PackageParser.Package pkg = packageParser.parsePackage(sourceFile, archiveFilePath,
- metrics, 0);
+ PackageParser.Package pkg = packageParser.parseMonolithicPackage(sourceFile, metrics, 0);
packageParser = null;
return pkg;
}
@@ -579,18 +578,18 @@
PackageParser.Package pkg;
- InstallParams(String outFileName, int rawResId) {
+ InstallParams(String outFileName, int rawResId) throws PackageParserException {
this.pkg = getParsedPackage(outFileName, rawResId);
- this.packageURI = Uri.fromFile(new File(pkg.mScanPath));
+ this.packageURI = Uri.fromFile(new File(pkg.codePath));
}
InstallParams(PackageParser.Package pkg) {
- this.packageURI = Uri.fromFile(new File(pkg.mScanPath));
+ this.packageURI = Uri.fromFile(new File(pkg.codePath));
this.pkg = pkg;
}
long getApkSize() {
- File file = new File(pkg.mScanPath);
+ File file = new File(pkg.codePath);
return file.length();
}
}
@@ -691,7 +690,8 @@
}
}
- private PackageParser.Package getParsedPackage(String outFileName, int rawResId) {
+ private PackageParser.Package getParsedPackage(String outFileName, int rawResId)
+ throws PackageParserException {
PackageManager pm = mContext.getPackageManager();
File filesDir = mContext.getFilesDir();
File outFile = new File(filesDir, outFileName);
@@ -1343,7 +1343,7 @@
assertUninstalled(info);
}
} finally {
- File outFile = new File(ip.pkg.mScanPath);
+ File outFile = new File(ip.pkg.codePath);
if (outFile != null && outFile.exists()) {
outFile.delete();
}
diff --git a/core/tests/coretests/src/android/net/IpPrefixTest.java b/core/tests/coretests/src/android/net/IpPrefixTest.java
new file mode 100644
index 0000000..cf278fb
--- /dev/null
+++ b/core/tests/coretests/src/android/net/IpPrefixTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.IpPrefix;
+import android.os.Parcel;
+import static android.test.MoreAsserts.assertNotEqual;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import static org.junit.Assert.assertArrayEquals;
+import java.net.InetAddress;
+import java.util.Random;
+import junit.framework.TestCase;
+
+
+public class IpPrefixTest extends TestCase {
+
+ // Explicitly cast everything to byte because "error: possible loss of precision".
+ private static final byte[] IPV4_BYTES = { (byte) 192, (byte) 0, (byte) 2, (byte) 4};
+ private static final byte[] IPV6_BYTES = {
+ (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8,
+ (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
+ (byte) 0x0f, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0
+ };
+
+ @SmallTest
+ public void testConstructor() {
+ IpPrefix p;
+ try {
+ p = new IpPrefix((byte[]) null, 9);
+ fail("Expected NullPointerException: null byte array");
+ } catch(RuntimeException expected) {}
+
+ try {
+ p = new IpPrefix((InetAddress) null, 10);
+ fail("Expected NullPointerException: null InetAddress");
+ } catch(RuntimeException expected) {}
+
+ try {
+ p = new IpPrefix((String) null);
+ fail("Expected NullPointerException: null String");
+ } catch(RuntimeException expected) {}
+
+
+ try {
+ byte[] b2 = {1, 2, 3, 4, 5};
+ p = new IpPrefix(b2, 29);
+ fail("Expected IllegalArgumentException: invalid array length");
+ } catch(IllegalArgumentException expected) {}
+
+ try {
+ p = new IpPrefix("1.2.3.4");
+ fail("Expected IllegalArgumentException: no prefix length");
+ } catch(IllegalArgumentException expected) {}
+
+ try {
+ p = new IpPrefix("1.2.3.4/");
+ fail("Expected IllegalArgumentException: empty prefix length");
+ } catch(IllegalArgumentException expected) {}
+
+ try {
+ p = new IpPrefix("foo/32");
+ fail("Expected IllegalArgumentException: invalid address");
+ } catch(IllegalArgumentException expected) {}
+
+ try {
+ p = new IpPrefix("1/32");
+ fail("Expected IllegalArgumentException: deprecated IPv4 format");
+ } catch(IllegalArgumentException expected) {}
+
+ try {
+ p = new IpPrefix("1.2.3.256/32");
+ fail("Expected IllegalArgumentException: invalid IPv4 address");
+ } catch(IllegalArgumentException expected) {}
+
+ try {
+ p = new IpPrefix("foo/32");
+ fail("Expected IllegalArgumentException: non-address");
+ } catch(IllegalArgumentException expected) {}
+
+ try {
+ p = new IpPrefix("f00:::/32");
+ fail("Expected IllegalArgumentException: invalid IPv6 address");
+ } catch(IllegalArgumentException expected) {}
+ }
+
+ public void testTruncation() {
+ IpPrefix p;
+
+ p = new IpPrefix(IPV4_BYTES, 32);
+ assertEquals("192.0.2.4/32", p.toString());
+
+ p = new IpPrefix(IPV4_BYTES, 29);
+ assertEquals("192.0.2.0/29", p.toString());
+
+ p = new IpPrefix(IPV4_BYTES, 8);
+ assertEquals("192.0.0.0/8", p.toString());
+
+ p = new IpPrefix(IPV4_BYTES, 0);
+ assertEquals("0.0.0.0/0", p.toString());
+
+ try {
+ p = new IpPrefix(IPV4_BYTES, 33);
+ fail("Expected IllegalArgumentException: invalid prefix length");
+ } catch(RuntimeException expected) {}
+
+ try {
+ p = new IpPrefix(IPV4_BYTES, 128);
+ fail("Expected IllegalArgumentException: invalid prefix length");
+ } catch(RuntimeException expected) {}
+
+ try {
+ p = new IpPrefix(IPV4_BYTES, -1);
+ fail("Expected IllegalArgumentException: negative prefix length");
+ } catch(RuntimeException expected) {}
+
+ p = new IpPrefix(IPV6_BYTES, 128);
+ assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString());
+
+ p = new IpPrefix(IPV6_BYTES, 122);
+ assertEquals("2001:db8:dead:beef:f00::80/122", p.toString());
+
+ p = new IpPrefix(IPV6_BYTES, 64);
+ assertEquals("2001:db8:dead:beef::/64", p.toString());
+
+ p = new IpPrefix(IPV6_BYTES, 3);
+ assertEquals("2000::/3", p.toString());
+
+ p = new IpPrefix(IPV6_BYTES, 0);
+ assertEquals("::/0", p.toString());
+
+ try {
+ p = new IpPrefix(IPV6_BYTES, -1);
+ fail("Expected IllegalArgumentException: negative prefix length");
+ } catch(RuntimeException expected) {}
+
+ try {
+ p = new IpPrefix(IPV6_BYTES, 129);
+ fail("Expected IllegalArgumentException: negative prefix length");
+ } catch(RuntimeException expected) {}
+
+ }
+
+ private void assertAreEqual(Object o1, Object o2) {
+ assertTrue(o1.equals(o2));
+ assertTrue(o2.equals(o1));
+ }
+
+ private void assertAreNotEqual(Object o1, Object o2) {
+ assertFalse(o1.equals(o2));
+ assertFalse(o2.equals(o1));
+ }
+
+ @SmallTest
+ public void testEquals() {
+ IpPrefix p1, p2;
+
+ p1 = new IpPrefix("192.0.2.251/23");
+ p2 = new IpPrefix(new byte[]{(byte) 192, (byte) 0, (byte) 2, (byte) 251}, 23);
+ assertAreEqual(p1, p2);
+
+ p1 = new IpPrefix("192.0.2.5/23");
+ assertAreEqual(p1, p2);
+
+ p1 = new IpPrefix("192.0.2.5/24");
+ assertAreNotEqual(p1, p2);
+
+ p1 = new IpPrefix("192.0.4.5/23");
+ assertAreNotEqual(p1, p2);
+
+
+ p1 = new IpPrefix("2001:db8:dead:beef:f00::80/122");
+ p2 = new IpPrefix(IPV6_BYTES, 122);
+ assertEquals("2001:db8:dead:beef:f00::80/122", p2.toString());
+ assertAreEqual(p1, p2);
+
+ p1 = new IpPrefix("2001:db8:dead:beef:f00::bf/122");
+ assertAreEqual(p1, p2);
+
+ p1 = new IpPrefix("2001:db8:dead:beef:f00::8:0/123");
+ assertAreNotEqual(p1, p2);
+
+ p1 = new IpPrefix("2001:db8:dead:beef::/122");
+ assertAreNotEqual(p1, p2);
+
+ // 192.0.2.4/32 != c000:0204::/32.
+ byte[] ipv6bytes = new byte[16];
+ System.arraycopy(IPV4_BYTES, 0, ipv6bytes, 0, IPV4_BYTES.length);
+ p1 = new IpPrefix(ipv6bytes, 32);
+ assertAreEqual(p1, new IpPrefix("c000:0204::/32"));
+
+ p2 = new IpPrefix(IPV4_BYTES, 32);
+ assertAreNotEqual(p1, p2);
+ }
+
+ @SmallTest
+ public void testHashCode() {
+ IpPrefix p;
+ int oldCode = -1;
+ Random random = new Random();
+ for (int i = 0; i < 100; i++) {
+ if (random.nextBoolean()) {
+ // IPv4.
+ byte[] b = new byte[4];
+ random.nextBytes(b);
+ p = new IpPrefix(b, random.nextInt(33));
+ assertNotEqual(oldCode, p.hashCode());
+ oldCode = p.hashCode();
+ } else {
+ // IPv6.
+ byte[] b = new byte[16];
+ random.nextBytes(b);
+ p = new IpPrefix(b, random.nextInt(129));
+ assertNotEqual(oldCode, p.hashCode());
+ oldCode = p.hashCode();
+ }
+ }
+ }
+
+ @SmallTest
+ public void testMappedAddressesAreBroken() {
+ // 192.0.2.0/24 != ::ffff:c000:0204/120, but because we use InetAddress,
+ // we are unable to comprehend that.
+ byte[] ipv6bytes = {
+ (byte) 0, (byte) 0, (byte) 0, (byte) 0,
+ (byte) 0, (byte) 0, (byte) 0, (byte) 0,
+ (byte) 0, (byte) 0, (byte) 0xff, (byte) 0xff,
+ (byte) 192, (byte) 0, (byte) 2, (byte) 0};
+ IpPrefix p = new IpPrefix(ipv6bytes, 120);
+ assertEquals(16, p.getRawAddress().length); // Fine.
+ assertArrayEquals(ipv6bytes, p.getRawAddress()); // Fine.
+
+ // Broken.
+ assertEquals("192.0.2.0/120", p.toString());
+ assertEquals(InetAddress.parseNumericAddress("192.0.2.0"), p.getAddress());
+ }
+
+ public IpPrefix passThroughParcel(IpPrefix p) {
+ Parcel parcel = Parcel.obtain();
+ IpPrefix p2 = null;
+ try {
+ p.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ p2 = IpPrefix.CREATOR.createFromParcel(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ assertNotNull(p2);
+ return p2;
+ }
+
+ public void assertParcelingIsLossless(IpPrefix p) {
+ IpPrefix p2 = passThroughParcel(p);
+ assertEquals(p, p2);
+ }
+
+ public void testParceling() {
+ IpPrefix p;
+
+ p = new IpPrefix("2001:4860:db8::/64");
+ assertParcelingIsLossless(p);
+
+ p = new IpPrefix("192.0.2.0/25");
+ assertParcelingIsLossless(p);
+ }
+}
diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/core/tests/coretests/src/android/net/LinkAddressTest.java
index bccf556..7bc3974 100644
--- a/core/tests/coretests/src/android/net/LinkAddressTest.java
+++ b/core/tests/coretests/src/android/net/LinkAddressTest.java
@@ -30,6 +30,7 @@
import android.net.LinkAddress;
import android.os.Parcel;
import android.test.AndroidTestCase;
+import static android.test.MoreAsserts.assertNotEqual;
import android.test.suitebuilder.annotation.SmallTest;
import static android.system.OsConstants.IFA_F_DEPRECATED;
@@ -50,32 +51,43 @@
private static final InetAddress V4_ADDRESS = NetworkUtils.numericToInetAddress(V4);
private static final InetAddress V6_ADDRESS = NetworkUtils.numericToInetAddress(V6);
+ public void testConstants() {
+ // RT_SCOPE_UNIVERSE = 0, but all the other constants should be nonzero.
+ assertNotEqual(0, RT_SCOPE_HOST);
+ assertNotEqual(0, RT_SCOPE_LINK);
+ assertNotEqual(0, RT_SCOPE_SITE);
+
+ assertNotEqual(0, IFA_F_DEPRECATED);
+ assertNotEqual(0, IFA_F_PERMANENT);
+ assertNotEqual(0, IFA_F_TENTATIVE);
+ }
+
public void testConstructors() throws SocketException {
LinkAddress address;
// Valid addresses work as expected.
address = new LinkAddress(V4_ADDRESS, 25);
assertEquals(V4_ADDRESS, address.getAddress());
- assertEquals(25, address.getNetworkPrefixLength());
+ assertEquals(25, address.getPrefixLength());
assertEquals(0, address.getFlags());
assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
address = new LinkAddress(V6_ADDRESS, 127);
assertEquals(V6_ADDRESS, address.getAddress());
- assertEquals(127, address.getNetworkPrefixLength());
+ assertEquals(127, address.getPrefixLength());
assertEquals(0, address.getFlags());
assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
// Nonsensical flags/scopes or combinations thereof are acceptable.
address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK);
assertEquals(V6_ADDRESS, address.getAddress());
- assertEquals(64, address.getNetworkPrefixLength());
+ assertEquals(64, address.getPrefixLength());
assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags());
assertEquals(RT_SCOPE_LINK, address.getScope());
address = new LinkAddress(V4 + "/23", 123, 456);
assertEquals(V4_ADDRESS, address.getAddress());
- assertEquals(23, address.getNetworkPrefixLength());
+ assertEquals(23, address.getPrefixLength());
assertEquals(123, address.getFlags());
assertEquals(456, address.getScope());
@@ -94,10 +106,10 @@
}
assertEquals(NetworkUtils.numericToInetAddress("127.0.0.1"), ipv4Loopback.getAddress());
- assertEquals(8, ipv4Loopback.getNetworkPrefixLength());
+ assertEquals(8, ipv4Loopback.getPrefixLength());
assertEquals(NetworkUtils.numericToInetAddress("::1"), ipv6Loopback.getAddress());
- assertEquals(128, ipv6Loopback.getNetworkPrefixLength());
+ assertEquals(128, ipv6Loopback.getPrefixLength());
// Null addresses are rejected.
try {
diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
index 553afe0..e649baa 100644
--- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java
+++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
@@ -88,8 +88,8 @@
source.addLinkAddress(LINKADDRV4);
source.addLinkAddress(LINKADDRV6);
// set 2 dnses
- source.addDns(DNS1);
- source.addDns(DNS2);
+ source.addDnsServer(DNS1);
+ source.addDnsServer(DNS2);
// set 2 gateways
source.addRoute(new RouteInfo(GATEWAY1));
source.addRoute(new RouteInfo(GATEWAY2));
@@ -101,8 +101,8 @@
target.setInterfaceName(NAME);
target.addLinkAddress(LINKADDRV4);
target.addLinkAddress(LINKADDRV6);
- target.addDns(DNS1);
- target.addDns(DNS2);
+ target.addDnsServer(DNS1);
+ target.addDnsServer(DNS2);
target.addRoute(new RouteInfo(GATEWAY1));
target.addRoute(new RouteInfo(GATEWAY2));
target.setMtu(MTU);
@@ -114,8 +114,8 @@
target.setInterfaceName("qmi1");
target.addLinkAddress(LINKADDRV4);
target.addLinkAddress(LINKADDRV6);
- target.addDns(DNS1);
- target.addDns(DNS2);
+ target.addDnsServer(DNS1);
+ target.addDnsServer(DNS2);
target.addRoute(new RouteInfo(GATEWAY1));
target.addRoute(new RouteInfo(GATEWAY2));
target.setMtu(MTU);
@@ -127,8 +127,8 @@
target.addLinkAddress(new LinkAddress(
NetworkUtils.numericToInetAddress("75.208.6.2"), 32));
target.addLinkAddress(LINKADDRV6);
- target.addDns(DNS1);
- target.addDns(DNS2);
+ target.addDnsServer(DNS1);
+ target.addDnsServer(DNS2);
target.addRoute(new RouteInfo(GATEWAY1));
target.addRoute(new RouteInfo(GATEWAY2));
target.setMtu(MTU);
@@ -139,8 +139,8 @@
target.addLinkAddress(LINKADDRV4);
target.addLinkAddress(LINKADDRV6);
// change dnses
- target.addDns(NetworkUtils.numericToInetAddress("75.208.7.2"));
- target.addDns(DNS2);
+ target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2"));
+ target.addDnsServer(DNS2);
target.addRoute(new RouteInfo(GATEWAY1));
target.addRoute(new RouteInfo(GATEWAY2));
target.setMtu(MTU);
@@ -150,8 +150,8 @@
target.setInterfaceName(NAME);
target.addLinkAddress(LINKADDRV4);
target.addLinkAddress(LINKADDRV6);
- target.addDns(DNS1);
- target.addDns(DNS2);
+ target.addDnsServer(DNS1);
+ target.addDnsServer(DNS2);
// change gateway
target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2")));
target.addRoute(new RouteInfo(GATEWAY2));
@@ -162,8 +162,8 @@
target.setInterfaceName(NAME);
target.addLinkAddress(LINKADDRV4);
target.addLinkAddress(LINKADDRV6);
- target.addDns(DNS1);
- target.addDns(DNS2);
+ target.addDnsServer(DNS1);
+ target.addDnsServer(DNS2);
target.addRoute(new RouteInfo(GATEWAY1));
target.addRoute(new RouteInfo(GATEWAY2));
// change mtu
@@ -185,8 +185,8 @@
source.addLinkAddress(LINKADDRV4);
source.addLinkAddress(LINKADDRV6);
// set 2 dnses
- source.addDns(DNS1);
- source.addDns(DNS2);
+ source.addDnsServer(DNS1);
+ source.addDnsServer(DNS2);
// set 2 gateways
source.addRoute(new RouteInfo(GATEWAY1));
source.addRoute(new RouteInfo(GATEWAY2));
@@ -197,8 +197,8 @@
target.setInterfaceName(NAME);
target.addLinkAddress(LINKADDRV6);
target.addLinkAddress(LINKADDRV4);
- target.addDns(DNS2);
- target.addDns(DNS1);
+ target.addDnsServer(DNS2);
+ target.addDnsServer(DNS1);
target.addRoute(new RouteInfo(GATEWAY2));
target.addRoute(new RouteInfo(GATEWAY1));
target.setMtu(MTU);
diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java
index 55d6592..af6a32b 100644
--- a/core/tests/coretests/src/android/net/RouteInfoTest.java
+++ b/core/tests/coretests/src/android/net/RouteInfoTest.java
@@ -19,7 +19,7 @@
import java.lang.reflect.Method;
import java.net.InetAddress;
-import android.net.LinkAddress;
+import android.net.IpPrefix;
import android.net.RouteInfo;
import android.os.Parcel;
@@ -32,9 +32,8 @@
return InetAddress.parseNumericAddress(addr);
}
- private LinkAddress Prefix(String prefix) {
- String[] parts = prefix.split("/");
- return new LinkAddress(Address(parts[0]), Integer.parseInt(parts[1]));
+ private IpPrefix Prefix(String prefix) {
+ return new IpPrefix(prefix);
}
@SmallTest
@@ -43,17 +42,17 @@
// Invalid input.
try {
- r = new RouteInfo(null, null, "rmnet0");
+ r = new RouteInfo((IpPrefix) null, null, "rmnet0");
fail("Expected RuntimeException: destination and gateway null");
} catch(RuntimeException e) {}
// Null destination is default route.
- r = new RouteInfo(null, Address("2001:db8::1"), null);
+ r = new RouteInfo((IpPrefix) null, Address("2001:db8::1"), null);
assertEquals(Prefix("::/0"), r.getDestination());
assertEquals(Address("2001:db8::1"), r.getGateway());
assertNull(r.getInterface());
- r = new RouteInfo(null, Address("192.0.2.1"), "wlan0");
+ r = new RouteInfo((IpPrefix) null, Address("192.0.2.1"), "wlan0");
assertEquals(Prefix("0.0.0.0/0"), r.getDestination());
assertEquals(Address("192.0.2.1"), r.getGateway());
assertEquals("wlan0", r.getInterface());
@@ -71,17 +70,19 @@
}
public void testMatches() {
- class PatchedRouteInfo extends RouteInfo {
- public PatchedRouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
- super(destination, gateway, iface);
+ class PatchedRouteInfo {
+ private final RouteInfo mRouteInfo;
+
+ public PatchedRouteInfo(IpPrefix destination, InetAddress gateway, String iface) {
+ mRouteInfo = new RouteInfo(destination, gateway, iface);
}
public boolean matches(InetAddress destination) {
- return super.matches(destination);
+ return mRouteInfo.matches(destination);
}
}
- RouteInfo r;
+ PatchedRouteInfo r;
r = new PatchedRouteInfo(Prefix("2001:db8:f00::ace:d00d/127"), null, "rmnet0");
assertTrue(r.matches(Address("2001:db8:f00::ace:d00c")));
@@ -96,11 +97,11 @@
assertFalse(r.matches(Address("192.0.0.21")));
assertFalse(r.matches(Address("8.8.8.8")));
- RouteInfo ipv6Default = new PatchedRouteInfo(Prefix("::/0"), null, "rmnet0");
+ PatchedRouteInfo ipv6Default = new PatchedRouteInfo(Prefix("::/0"), null, "rmnet0");
assertTrue(ipv6Default.matches(Address("2001:db8::f00")));
assertFalse(ipv6Default.matches(Address("192.0.2.1")));
- RouteInfo ipv4Default = new PatchedRouteInfo(Prefix("0.0.0.0/0"), null, "rmnet0");
+ PatchedRouteInfo ipv4Default = new PatchedRouteInfo(Prefix("0.0.0.0/0"), null, "rmnet0");
assertTrue(ipv4Default.matches(Address("255.255.255.255")));
assertTrue(ipv4Default.matches(Address("192.0.2.1")));
assertFalse(ipv4Default.matches(Address("2001:db8::f00")));
diff --git a/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
index 7d72f3e..d850c7c 100644
--- a/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
+++ b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
@@ -21,7 +21,7 @@
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.inputmethod.CursorAnchorInfo;
-import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder;
+import android.view.inputmethod.CursorAnchorInfo.Builder;
public class CursorAnchorInfoTest extends InstrumentationTestCase {
// null represents a character that is invisible, for example because it's overlapped by some
@@ -64,7 +64,7 @@
Matrix TRANSFORM_MATRIX = new Matrix(Matrix.IDENTITY_MATRIX);
TRANSFORM_MATRIX.setScale(10.0f, 20.0f);
- final CursorAnchorInfoBuilder builder = new CursorAnchorInfoBuilder();
+ final Builder builder = new Builder();
builder.setSelectionRange(SELECTION_START, SELECTION_END)
.setComposingText(COMPOSING_TEXT_START, COMPOSING_TEXT)
.setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP,
@@ -148,7 +148,7 @@
final Matrix MATRIX3 = new Matrix();
MATRIX3.setTranslate(210.0f, 220.0f);
final Matrix matrix = new Matrix();
- final CursorAnchorInfoBuilder builder = new CursorAnchorInfoBuilder();
+ final Builder builder = new Builder();
matrix.set(MATRIX1);
builder.setMatrix(matrix);
@@ -171,7 +171,7 @@
public void testBuilderAdd() throws Exception {
// A negative index should be rejected.
try {
- new CursorAnchorInfoBuilder().addCharacterRect(-1, 0.0f, 0.0f, 0.0f, 0.0f);
+ new Builder().addCharacterRect(-1, 0.0f, 0.0f, 0.0f, 0.0f);
} catch (IllegalArgumentException ex) {
assertTrue(true);
}
@@ -191,4 +191,3 @@
}
}
}
-
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
index 58b7db9..42de9ea 100644
--- a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
@@ -36,8 +36,7 @@
}
}
- private void setLocale(String code) {
- Locale locale = new Locale(code);
+ private void setLocale(Locale locale) {
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
@@ -268,193 +267,193 @@
*/
public void testMatrix100000() throws Throwable {
final int resId = R.integer.matrix_100000;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 100, 100);
}
public void testMatrix100001() throws Throwable {
final int resId = R.integer.matrix_100001;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 100, 600);
}
public void testMatrix100010() throws Throwable {
final int resId = R.integer.matrix_100010;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 100, 500);
}
public void testMatrix100011() throws Throwable {
final int resId = R.integer.matrix_100011;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 100, 600);
}
public void testMatrix100100() throws Throwable {
final int resId = R.integer.matrix_100100;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 400);
}
public void testMatrix100101() throws Throwable {
final int resId = R.integer.matrix_100101;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 600);
}
public void testMatrix100110() throws Throwable {
final int resId = R.integer.matrix_100110;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 400);
}
public void testMatrix100111() throws Throwable {
final int resId = R.integer.matrix_100111;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 600);
}
public void testMatrix101000() throws Throwable {
final int resId = R.integer.matrix_101000;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 300, 300);
}
public void testMatrix101001() throws Throwable {
final int resId = R.integer.matrix_101001;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 300, 600);
}
public void testMatrix101010() throws Throwable {
final int resId = R.integer.matrix_101010;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 300, 500);
}
public void testMatrix101011() throws Throwable {
final int resId = R.integer.matrix_101011;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 300, 600);
}
public void testMatrix101100() throws Throwable {
final int resId = R.integer.matrix_101100;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 400);
}
public void testMatrix101101() throws Throwable {
final int resId = R.integer.matrix_101101;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 600);
}
public void testMatrix101110() throws Throwable {
final int resId = R.integer.matrix_101110;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 400);
}
public void testMatrix101111() throws Throwable {
final int resId = R.integer.matrix_101111;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 100, 400, 600);
}
public void testMatrix110000() throws Throwable {
final int resId = R.integer.matrix_110000;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 200);
}
public void testMatrix110001() throws Throwable {
final int resId = R.integer.matrix_110001;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 600);
}
public void testMatrix110010() throws Throwable {
final int resId = R.integer.matrix_110010;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 200);
}
public void testMatrix110011() throws Throwable {
final int resId = R.integer.matrix_110011;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 600);
}
public void testMatrix110100() throws Throwable {
final int resId = R.integer.matrix_110100;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 400);
}
public void testMatrix110101() throws Throwable {
final int resId = R.integer.matrix_110101;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 600);
}
public void testMatrix110110() throws Throwable {
final int resId = R.integer.matrix_110110;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 400);
}
public void testMatrix110111() throws Throwable {
final int resId = R.integer.matrix_110111;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 600);
}
public void testMatrix111000() throws Throwable {
final int resId = R.integer.matrix_111000;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 200);
}
public void testMatrix111001() throws Throwable {
final int resId = R.integer.matrix_111001;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 600);
}
public void testMatrix111010() throws Throwable {
final int resId = R.integer.matrix_111010;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 200);
}
public void testMatrix111011() throws Throwable {
final int resId = R.integer.matrix_111011;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 200, 600);
}
public void testMatrix111100() throws Throwable {
final int resId = R.integer.matrix_111100;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 400);
}
public void testMatrix111101() throws Throwable {
final int resId = R.integer.matrix_111101;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 600);
}
public void testMatrix111110() throws Throwable {
final int resId = R.integer.matrix_111110;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 400);
}
public void testMatrix111111() throws Throwable {
final int resId = R.integer.matrix_111111;
- setLocale("sv_SE");
+ setLocale(new Locale("sv", "SE"));
assertResource(resId, 200, 400, 600);
}
}
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index c6bccfe..6437e07 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -42,12 +42,21 @@
$(eval $(call create-font-symlink,DroidSerif-Italic.ttf,NotoSerif-Italic.ttf))
$(eval $(call create-font-symlink,DroidSerif-BoldItalic.ttf,NotoSerif-BoldItalic.ttf))
+extra_font_files := \
+ DroidSans.ttf \
+ DroidSans-Bold.ttf
+
################################
# On space-constrained devices, we include a subset of fonts:
ifeq ($(SMALLER_FONT_FOOTPRINT),true)
+
droidsans_fallback_src := DroidSansFallback.ttf
-extra_font_files := DroidSans.ttf DroidSans-Bold.ttf
-else
+
+else # !SMALLER_FONT_FOOTPRINT
+
+droidsans_fallback_src := DroidSansFallbackFull.ttf
+
+ifneq ($(EXTENDED_FONT_FOOTPRINT),true)
include $(CLEAR_VARS)
LOCAL_MODULE := MTLmr3m.ttf
LOCAL_SRC_FILES := $(LOCAL_MODULE)
@@ -55,12 +64,9 @@
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
include $(BUILD_PREBUILT)
+extra_font_files += MTLmr3m.ttf
+endif # !EXTENDED_FONT_FOOTPRINT
-droidsans_fallback_src := DroidSansFallbackFull.ttf
-extra_font_files := \
- DroidSans.ttf \
- DroidSans-Bold.ttf \
- MTLmr3m.ttf
endif # SMALLER_FONT_FOOTPRINT
################################
@@ -106,6 +112,7 @@
ifeq ($(MINIMAL_FONT_FOOTPRINT),true)
$(eval $(call create-font-symlink,Roboto-Black.ttf,Roboto-Bold.ttf))
+$(eval $(call create-font-symlink,Roboto-BlackItalic.ttf,Roboto-BoldItalic.ttf))
$(eval $(call create-font-symlink,Roboto-Light.ttf,Roboto-Regular.ttf))
$(eval $(call create-font-symlink,Roboto-LightItalic.ttf,Roboto-Italic.ttf))
$(eval $(call create-font-symlink,Roboto-Medium.ttf,Roboto-Regular.ttf))
@@ -120,6 +127,7 @@
else # !MINIMAL_FONT
font_src_files += \
Roboto-Black.ttf \
+ Roboto-BlackItalic.ttf \
Roboto-Light.ttf \
Roboto-LightItalic.ttf \
Roboto-Medium.ttf \
diff --git a/data/fonts/Roboto-BlackItalic.ttf b/data/fonts/Roboto-BlackItalic.ttf
new file mode 100644
index 0000000..3ebdc7d
--- /dev/null
+++ b/data/fonts/Roboto-BlackItalic.ttf
Binary files differ
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index c2d5afe..1eaae65 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -219,6 +219,26 @@
</family>
<family>
<fileset>
+ <file lang="zh-CN">NotoSansHans-Regular.otf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file lang="zh-TW">NotoSansHant-Regular.otf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file lang="ja">NotoSansJP-Regular.otf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file lang="ko">NotoSansKR-Regular.otf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
<file>NanumGothic.ttf</file>
</fileset>
</family>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index e5573bb..70fc6a2 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -25,6 +25,7 @@
Roboto-Italic.ttf \
Roboto-BoldItalic.ttf \
Roboto-Black.ttf \
+ Roboto-BlackItalic.ttf \
Roboto-Light.ttf \
Roboto-LightItalic.ttf \
Roboto-Medium.ttf \
diff --git a/data/fonts/system_fonts.xml b/data/fonts/system_fonts.xml
index 646b33b..8c59fea 100644
--- a/data/fonts/system_fonts.xml
+++ b/data/fonts/system_fonts.xml
@@ -82,6 +82,7 @@
</nameset>
<fileset>
<file>Roboto-Black.ttf</file>
+ <file>Roboto-BlackItalic.ttf</file>
</fileset>
</family>
diff --git a/docs/html/auto/images/carlogos.png b/docs/html/auto/images/carlogos.png
new file mode 100644
index 0000000..3522aa3
--- /dev/null
+++ b/docs/html/auto/images/carlogos.png
Binary files differ
diff --git a/docs/html/auto/images/figure01.png b/docs/html/auto/images/figure01.png
new file mode 100644
index 0000000..3044020
--- /dev/null
+++ b/docs/html/auto/images/figure01.png
Binary files differ
diff --git a/docs/html/auto/images/figure02.png b/docs/html/auto/images/figure02.png
new file mode 100644
index 0000000..1b87224
--- /dev/null
+++ b/docs/html/auto/images/figure02.png
Binary files differ
diff --git a/docs/html/auto/images/figure03.png b/docs/html/auto/images/figure03.png
new file mode 100644
index 0000000..0c4e20d
--- /dev/null
+++ b/docs/html/auto/images/figure03.png
Binary files differ
diff --git a/docs/html/auto/images/figure04.png b/docs/html/auto/images/figure04.png
new file mode 100644
index 0000000..3e9c894
--- /dev/null
+++ b/docs/html/auto/images/figure04.png
Binary files differ
diff --git a/docs/html/auto/images/figure05.png b/docs/html/auto/images/figure05.png
new file mode 100644
index 0000000..9c1d9b8
--- /dev/null
+++ b/docs/html/auto/images/figure05.png
Binary files differ
diff --git a/docs/html/auto/images/figure06.png b/docs/html/auto/images/figure06.png
new file mode 100644
index 0000000..8140f0c
--- /dev/null
+++ b/docs/html/auto/images/figure06.png
Binary files differ
diff --git a/docs/html/auto/images/figure07.png b/docs/html/auto/images/figure07.png
new file mode 100644
index 0000000..82c1c76
--- /dev/null
+++ b/docs/html/auto/images/figure07.png
Binary files differ
diff --git a/docs/html/auto/images/figure08.png b/docs/html/auto/images/figure08.png
new file mode 100644
index 0000000..f11e3a8
--- /dev/null
+++ b/docs/html/auto/images/figure08.png
Binary files differ
diff --git a/docs/html/auto/images/hero.jpg b/docs/html/auto/images/hero.jpg
new file mode 100644
index 0000000..3f9114f
--- /dev/null
+++ b/docs/html/auto/images/hero.jpg
Binary files differ
diff --git a/docs/html/auto/index.jd b/docs/html/auto/index.jd
new file mode 100644
index 0000000..c7a3a4e
--- /dev/null
+++ b/docs/html/auto/index.jd
@@ -0,0 +1,223 @@
+page.title=Android Auto
+page.viewport_width=970
+fullpage=true
+no_footer_links=true
+page.type=about
+
+@jd:body
+
+<style>
+.fullpage>#footer,
+#jd-content>.content-footer.wrap {
+ display:none;
+}
+</style>
+
+<style>
+#footer {
+ display: none;
+}
+.content-footer {
+ display: none;
+}
+#hero-height {
+ height:calc(100% - 100px);
+}
+</style>
+
+
+<div class="landing-body-content">
+ <div class="landing-hero-container">
+
+ <div id="hero-height" class="landing-section auto-hero">
+ <div class="landing-hero-scrim"></div>
+ <div class="landing-hero-wrap">
+ <div class="vertical-center-outer">
+ <div class="vertical-center-inner">
+
+ <div class="col-10">
+ <div class="landing-section-header">
+ <div class="landing-h1 hero">Android Auto</div>
+ <div class="landing-subhead hero">Entertainment and services on your dashboard</div>
+ <div class="landing-hero-description">
+ <p>Display and control your handheld app in vehicles.
+ Build apps with easy-to-use UI templates that
+ let users keep their eyes on the road.</p>
+ </div>
+
+ <div class="landing-body">
+ <a href="{@docRoot}auto/overview.html" class="landing-button landing-primary" style="margin-top: 40px;">
+ Developer Overview
+ </a>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div> <!-- end .wrap -->
+
+ <div class="landing-scroll-down-affordance">
+ <a class="landing-down-arrow" href="#android-in-car">
+ <img src="{@docRoot}wear/images/carrot.png" alt="Scroll down to read more">
+ </a>
+ </div>
+ </div> <!-- end .landing-section .landing-hero -->
+ </div> <!-- end .landing-hero-container -->
+
+ <div class="landing-rest-of-page">
+
+ <div class="landing-section landing-gray-background" id="android-in-car">
+ <div class="wrap">
+ <div class="landing-section-header">
+ <div class="landing-h1">Bringing Android to Your Car</div>
+ </div>
+
+ <div class="landing-body">
+ <p>When users connect their Android phone to an Android Auto enabled vehicle, the
+ system shows an interface that lets users select compatible apps and services to run.
+ </p>
+ <p>Android Auto provides new APIs and tools that your existing Android apps can
+ leverage to run on any compatible vehicle. Users interact with your apps through the
+ touch screen and the physical buttons on the vehicle’s dashboard. Your apps can also
+ respond to voice commands.
+ </p>
+ </div>
+
+ </div> <!-- end .wrap -->
+ </div> <!-- end .landing-section -->
+
+
+ <div class="landing-section">
+ <div class="wrap">
+ <div class="landing-section-header">
+ <div class="landing-h1">One Platform</div>
+ </div>
+
+ <div class="landing-body">
+ <p>Android Auto is an extension of the Android platform. You can easily adapt
+ existing apps for Android Auto and reuse many of the Android APIs and services you
+ are already familiar with.</p>
+ <p>The Android Auto platform and SDK let you write your apps only once, without having
+ to worry about vehicle-specific hardware differences like screen resolution, software
+ interfaces, knobs and touch controls. Your app runs the same on any compatible
+ vehicle.</p>
+ </div>
+ </div> <!-- end .wrap -->
+ </div> <!-- end .landing-section -->
+
+ <div class="landing-section landing-gray-background" >
+ <div class="wrap">
+ <div class="landing-section-header">
+ <div class="landing-h1">Minimizing Distraction</div>
+ </div>
+
+ <div class="landing-body">
+ <p>We designed Android Auto to minimize driver distraction. Android Auto provides UI
+ templates for several app categories. These templates define the user interaction model
+ for any app and follow international best practices for reducing driver distraction.</p>
+ <p>You can customize these templates to fit your brand and link them to your app’s
+ content and functionality, instead of building new UIs and testing them for driver
+ distraction, which is a lengthy and costly process.</p>
+ <p>Android Auto locks any device that users connect to a compatible vehicle, so drivers
+ interact with the device using voice actions and the vehicle’s input controls.</p>
+ </div>
+ </div> <!-- end .wrap -->
+ </div> <!-- end .landing-section -->
+
+ <div class="landing-section landing-white-background">
+ <div class="wrap">
+ <div class="landing-section-header">
+ <div class="landing-h1">Building an Ecosystem</div>
+ </div>
+ <div class="landing-body landing-align-center">
+ <p style="margin-bottom:20px">
+ Android Auto is coming soon to new cars from these manufacturers:
+ </p>
+ </div>
+ <div style="width:800px;margin:0 auto">
+ <img src="{@docRoot}auto/images/carlogos.png" alt="Partners" />
+ </div>
+ </div> <!-- end .wrap -->
+ </div> <!-- end .landing-section -->
+
+
+ <div class="landing-section" >
+ <div class="wrap">
+ <div class="landing-section-header">
+ <div class="landing-h1">Developer Stories</div>
+ </div>
+
+ <div class="landing-body">
+ <p>We're working with developers to bring many popular apps to Android Auto:</p>
+ <p>
+
+ </p>
+ </div>
+
+ </div> <!-- end .wrap -->
+ </div> <!-- end .landing-section -->
+
+
+ <div class="landing-section" style="background-color:#f5f5f5">
+ <div class="wrap">
+ <div class="landing-section-header">
+ <div class="landing-pre-h1">Coming soon</div>
+ <div class="landing-h1">Android Auto SDK</div>
+ <div style="text-align:center;margin-top:20px;font-size:14pt;margin-bottom:-5px">
+ <a href="https://docs.google.com/a/google.com/forms/d/1ANgYOoYLkfyZ2JRPSU34Nep5yNaU-Ha2syXJ9b4xLrA/viewform">Sign up for updates</a>
+ </div>
+ </div>
+
+ <div class="landing-body">
+ <p>In the coming months, we’ll be releasing the Android Auto SDK, which includes APIs
+ and tools to make your existing apps compatible with Android Auto. The first version
+ of the SDK will provide templates and APIs for music, podcast, live radio, and audio
+ news apps, as well as limited voice actions.</p>
+ <p style="margin-bottom:40px">
+ Future versions of the Android Auto SDK will include support for a selection of
+ Android notifications, additional voice actions, and templates and APIs for
+ messaging, communication, local search, and more.</p>
+
+ <a target="_blank" href="http://g.co/androidautodev">
+ <img class="landing-social-image" src="//www.google.com/images/icons/product/gplus-128.png" alt="+Android Auto Developers">
+ </a>
+ <p style="margin-bottom:5px">G+ Community</p>
+ <p class="landing-small">
+ Join the Android Auto developer community on Google+ to stay involved, get the
+ latest updates, and exchange experiences with other developers.
+ <a target="_blank" href="http://g.co/androidautodev">+Android Auto Developers</a>
+ </p>
+ </div>
+
+ </div> <!-- end .wrap -->
+ </div> <!-- end .landing-section -->
+
+ </div> <!-- end .landing-rest-of-page -->
+
+
+ <div class="content-footer wrap" itemscope="" itemtype="http://schema.org/SiteNavigationElement">
+ <div class="layout-content-col col-16" style="padding-top:4px">
+ <style>#___plusone_0 {float:right !important;}</style>
+ <div class="g-plusone" data-size="medium"></div>
+ </div>
+ </div>
+ <div id="footer" class="wrap" style="width:940px;position:relative;top:-35px;z-index:-1">
+ <div id="copyright">
+ Except as noted, this content is
+ licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
+ Creative Commons Attribution 2.5</a>. For details and
+ restrictions, see the <a href="/license.html">Content
+ License</a>.
+ </div>
+ </div>
+
+
+ </div> <!-- end landing-body-content -->
+
+ <script>
+ $("a.landing-down-arrow").on("click", function(e) {
+ $("body").animate({
+ scrollTop: $(".auto-hero").height() + 120
+ }, 1000, "easeOutQuint");
+ e.preventDefault();
+ });
+ </script>
diff --git a/docs/html/auto/overview.jd b/docs/html/auto/overview.jd
new file mode 100644
index 0000000..8748bff
--- /dev/null
+++ b/docs/html/auto/overview.jd
@@ -0,0 +1,363 @@
+fullpage=true
+page.viewport_width=970
+no_footer_links=true
+excludeFromSuggestions=true
+page.metaDescription=Android Auto
+
+@jd:body
+
+<style>
+.jd-descr {
+ height:auto;
+}
+#copyright {
+ margin-top:-35px;
+}
+</style>
+
+<div style="width:780px; margin:0 auto;">
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+ <li><a href="#design">Design</a>
+ <ol>
+ <li><a href="#designprinciples">Design Principles</a></li>
+ <li><a href="#uioverview">UI Overview</a></li>
+ </ol>
+ </li>
+ <li><a href="#architecture">Architecture</a></li>
+ <li><a href="#uitemplates">UI Templates</a>
+ <ol>
+ <li><a href="#launchapp">Launch App</a></li>
+ <li><a href="#useractions">User Actions</a></li>
+ <li><a href="#drawertransitions">Drawer Transitions</a></li>
+ <li><a href="#daynighttransitions">Day and Night Transitions</a></li>
+ <li><a href="#customizetemplates">Customizing Templates</a></li>
+ </ol>
+ </li>
+ <li><a href="#devprocess">Development Process</a></li>
+ <li><a href="#emulator">Testing Your App</a></li>
+ <li><a href="#running">Running Your App</a></li>
+</ol>
+</div>
+</div>
+
+<h1>Android Auto Developer Overview</h1>
+
+<p>Android Auto extends the Android platform to car entertainment systems. When users connect
+their Android handheld device to a compatible vehicle, Android Auto lets users project apps on
+the vehicle’s touchscreen and interact with them using the vehicle’s controls.</p>
+
+<dl>
+<dt style="margin-bottom:10px"><strong>UI Templates</strong></dt>
+<dd style="margin-bottom:20px">
+Android Auto defines interaction models and UI templates for several app categories. The
+first version of Android Auto supports media apps, such as music, podcast, live radio, and
+audio news apps. Future versions will support messaging, communication, local search apps,
+and more.
+</dd>
+<dt style="margin-bottom:10px"><strong>Notifications</strong></dt>
+<dd style="margin-bottom:20px">
+The platform will integrate with existing Android APIs for notifications. Users will get
+some notifications from Android apps on the vehicle’s screen.</dd>
+
+<dt style="margin-bottom:10px"><strong>Voice Actions</strong></dt>
+<dd style="margin-bottom:20px">
+Android Auto supports voice search and voice actions for media apps. Future versions
+will support additional voice actions.</dd>
+
+<dt style="margin-bottom:10px"><strong>Easy Development Workflow</strong></dt>
+<dd style="margin-bottom:20px">
+To extend an existing Android app for Android Auto, you implement a set of interfaces and
+services defined in the platform. You can reuse existing functionality and many Android APIs
+you already know.</dd>
+</dl>
+
+<p>We’ll release the Android Auto SDK in the coming months, which will let you test your
+Android Auto experience on a regular Android device.</p>
+
+
+<h2 id="design" style="margin-top:30px">Design</h2>
+
+<p>Digital experiences for cars should complement and augment driving, not demand the driver's
+attention. Designing these experiences for cars is fundamentally different than in the case of
+phones and tablets. It requires rethinking how these experiences unfold.</p>
+
+<h3 id="designprinciples" style="margin-top:25px">Design Principles</h3>
+
+<p><strong>Glanceable</strong>. We designed Android Auto to reduce UI complexity, optimize user
+interactions, and lower cognitive load. Effective apps show just enough information
+and only provide features that do not require excessive menu interaction and navigation.</p>
+
+<p><strong>Predictive, yet predictable</strong>. Android Auto leverages rich, contextual awareness
+to keep the driver informed about important situations. Timely help is combined with predictable
+functions. Effective apps use patterns for common tasks and show timely information only when
+relevant.</p>
+
+<p><strong>Connected</strong>. Android Auto works with apps that drivers already use in other
+devices. Android Auto promotes a continuous app experience from phones and tablets to cars,
+providing access to user's existing settings, subscriptions, and digital libraries. Experiences
+that bring personal content and context from other devices are part of Android Auto.</p>
+
+<p><strong>Integrated</strong>. Android Auto blends your apps with the vehicle's entertainment
+system, creating a truly integrated experience in every car. By using the vehicle's screen and
+controls, apps feel tailored to each car.</p>
+
+<h3 id="uioverview" style="margin-top:25px">UI Overview</h3>
+
+<p>Android Auto is a new environment that leverages existing UI models where appropiate and adds
+new models based on constrains and context. There are three primary concepts for Android Auto:
+<strong>Suggest</strong>, a unified place for predictive content; <strong>Demand</strong>, a
+pervasive way to interact with voice; and the <strong>Facets</strong>, organized spaces for
+primary activities, apps and content.</p>
+
+<dl>
+<dt style="margin-bottom:10px"><strong>Suggest: The Google Facet</strong></dt>
+<dd style="margin-bottom:20px">
+Core of continuity and extensibility is contextual stream of Now-like cards, powered by your
+apps and notifications. Relevant, timely, and dynamic, the stream organizes likely people, media,
+places, and information so drivers can quickly continue their activities or start something new.
+Google Now and notifications enable drivers to use the apps and services they know when they are
+most relevant.
+</dd>
+<dt style="margin-bottom:10px"><strong>Demand: The Voice Layer</strong></dt>
+<dd style="margin-bottom:20px">
+Voice-enabled tasks lets drivers accomplish their goals without taking their eyes off the road.
+Android Auto defines actions and intents that your app can register for.
+These are accessible through both persistent UI elements and dedicated hardware controls.
+</dd>
+<dt style="margin-bottom:10px"><strong>Facets and Templates: App-powered activities</strong></dt>
+<dd style="margin-bottom:20px">
+In the car, pages of app icons and different UIs create a distracting and dangerous situation.
+Instead, Android Auto apps power templates which help provide simple but customizable UIs
+for common interactions such as media or communications. Templates incorporate common behaviors,
+such as play/pause or reply to a message, while still letting your app promote its value
+and its brand. Apps are organized into facets (or activities) to enable quick access.
+</dd>
+</dl>
+
+<p>Android Auto uses the input and output mechanisms in each vehicle to tailor the interactions.
+Some vehicles have dedicated hardware controls, while others have primarily touch-based systems.
+Android Auto maps common actions and intents across these diverse sets of controls and outputs to
+enable you to concentrate on your unique app experience.</p>
+
+
+<h2 id="architecture" style="margin-top:30px">Architecture</h2>
+
+<p>The Android Auto app projects your app's customized UI on the vehicle's screen. To communicate
+with the Android Auto app, your media app implements a set of media interfaces.</p>
+
+<div style="width:750px;margin:0 auto">
+<img src="/auto/images/figure01.png" alt="" id="figure1" />
+<p class="img-caption">
+ <strong>Figure 1</strong> - Architecture of Android Auto.
+</p>
+</div>
+
+<p>The architecture consists of the following components:</p>
+
+<p><strong>Media App</strong> - Runs a media service that exposes content through browsing and
+playback APIs. The service provides content to the Android Auto app. This is your Android app.</p>
+
+<p><strong>Android Auto App</strong> - Creates a templated UI and handles user interactions.
+This app uses a media client to request content from the media service running in the media
+app. The client requests data from the media service and monitors service states.</p>
+
+<p><strong>Vehicle Display</strong> - Shows app content and supports user interaction via
+on-screen soft buttons and other components, such as physical buttons or steering
+wheel controls.</p>
+
+<p>Android media apps must implement binders to these APIs:</p>
+
+<ul>
+<li><strong>Browsing</strong> - Enables a media client to browse a hierarchy of a user’s
+media collection, presented as a virtual file system with containers (similar to directories)
+and items (similar to files).</li>
+<li><strong>Playback</strong> - Enables a media client to control media playback and monitor
+playback state through callbacks.</li>
+</ul>
+
+
+<h2 id="uitemplates" style="margin-top:30px">UI Templates</h2>
+
+<p>The Android Auto app uses a templated UI to display content and user interaction
+opportunities. Android Auto provides you with a set of standard UI templates that follow
+international guidelines for minimizing driving distraction. You do not have to test your
+app's UI for for driver distraction, which is a lengthy and expensive process involving
+multiple legislations across the globe and different standards for each vehicle OEM.</p>
+
+<p>The UI templates define interfaces for browsing, searching, and listening to content from
+media apps. Although you cannot change the standard template format or layout, you can customize
+the template colors, action icons, background images, and more.</p>
+
+<h3 id="launchapp" style="margin-top:25px">Launch App Template</h3>
+
+<p>The Launcher template shows all the compatible media apps installed on the user’s
+Android device and lets users select one of them from an scrollable list:</p>
+
+<div style="width:500px;margin:0 auto">
+<img src="/auto/images/figure02.png" alt="" id="figure2" />
+<p class="img-caption">
+ <strong>Figure 2.</strong> The Launcher template.
+</p>
+</div>
+
+<h3 style="margin-top:25px">Primary App Template</h3>
+
+<p>After the user selects a media app, the display shows the primary app template. Figure
+3 shows the elements of this template that you can customize:</p>
+
+<div style="width:428px;margin:0 auto">
+<img src="/auto/images/figure03.png" alt="" id="figure3" />
+<p class="img-caption">
+ <strong>Figure 3.</strong> The main application template.
+</p>
+</div>
+
+<p>You can customize the primary app template to show your own icons, app name, and
+background images. Figure 4 shows an example of a customized template:</p>
+
+<div style="width:787px;margin:0 auto">
+<img src="/auto/images/figure04.png" alt="" id="figure4" />
+<p class="img-caption">
+ <strong>Figure 4.</strong> A customized template.
+</p>
+</div>
+
+<h3 id="useractions" style="margin-top:25px">User Actions</h3>
+
+<p>The primary app template supports four main actions on the action bar, four auxiliary actions
+on the overflow bar, and the <em>Return</em> action. You can use standard controls and customize
+the actions and icons, as shown in Figure 5.</p>
+
+<div style="width:500px;margin:0 auto">
+<img src="/auto/images/figure05.png" alt="" id="figure5" />
+<p class="img-caption">
+ <strong>Figure 5.</strong> Custom icons for auxiliary actions.
+</p>
+</div>
+
+<h3 id="drawertransitions" style="margin-top:25px">Drawer Transitions</h3>
+
+<p>For browse actions, the display shows the drawer transition and template:</p>
+
+<div style="width:750px;margin:0 auto">
+<img src="/auto/images/figure06.png" alt="" id="figure6" />
+<p class="img-caption">
+ <strong>Figure 6.</strong> The drawer transition.
+</p>
+</div>
+
+<p>After the transition from the primary app template to the drawer template, the drawer
+appears on the center. The customized drawer template shows the media containers and
+media files provided by the media service in your app. You can also customize drawers
+with icons for list items.</p>
+
+<div style="width:500px;margin:0 auto">
+<img src="/auto/images/figure07.png" alt="" id="figure7" />
+<p class="img-caption">
+ <strong>Figure 7.</strong> A customized drawer template.
+</p>
+</div>
+
+<h3 id="daynighttransitions" style="margin-top:25px">Day and Night Transitions</h3>
+
+<p>All the templates support different color schemes for day and night, as shown in
+Figure 8. The platform provides the state (day or night) and makes adjustments automatically.</p>
+
+<div style="width:780px;margin:0 auto">
+<img src="/auto/images/figure08.png" alt="" id="figure8" />
+<p class="img-caption">
+ <strong>Figure 8.</strong> Day and night transitions.
+</p>
+</div>
+
+<h3 id="customizetemplates" style="margin-top:25px">Customizing Templates</h3>
+
+<p>To customize the templates, provide the following app-specific resources and actions
+to the Android Auto media client.</p>
+
+<ul>
+<li><strong>Resources</strong> - App logo, app name, theme colors, and background images.</li>
+<li><strong>Actions</strong> - Multiple custom actions; for example: <em>Thumbs Up/Down</em>,
+<em>Favorite</em>, and <em>Bookmark</em>. These actions are app-specific.</li>
+</ul>
+
+<p>If provided, the media client automatically uses them in the templated UI.</p>
+
+
+<h2 id="devprocess" style="margin-top:30px">Development Process</h2>
+
+<p class="note"><strong>Note:</strong> When released, the Android Auto SDK will provide
+media service interfaces, an APK for handheld devices that simulates the Android Auto
+app, and other tools for Android Auto development.</p>
+
+<p>To create a media app for Android Auto, you include an Android service in your app
+that implements the media service interfaces provided by the Android Auto SDK. These
+interfaces define functionality for browsing and finding content, playing media,
+customizing the UI template, and performing app-specific actions.</p>
+
+<p>The media service interfaces present the content library as a navigable tree and enable
+clients to play media, get album art, obtain theme resources for the UI template, and
+invoke app-specific actions.</p>
+
+<p>You don’t have to create a new app for Android Auto: you can extend your existing
+Android app with implementations of the media service interfaces. Your service exposes
+your app’s media content, theme resources, and app-specific actions using the methods and
+data types specified by the media service interfaces. This simplifies the development
+cycle because:</p>
+
+<ul>
+<li>You do not have to maintain a separate project for Android Auto</li>
+<li>You can reuse existing functionality from your Android app</li>
+</ul>
+
+<p>The Android Auto client presents the customized UI to users and invokes the
+functionality from your service as needed. This has two additional advantages:</p>
+
+<ul>
+<li>Your app does not implement a UI for Android Auto</li>
+<li>Your app does not manage user interactions directly</li>
+</ul>
+
+<p>This also means that you do not have to worry about vehicle-specific hardware
+differences such as screen resolutions, software interfaces, knobs and touch
+controls.</p>
+
+
+<h2 id="emulator" style="margin-top:30px">Testing Your App on an Android Device</h2>
+
+<p>The Android Auto SDK includes an APK with a media client implementation, which is
+similar to those available in compatible vehicles. To test your app with this
+client:</p>
+
+<ol>
+<li>Get an Android device with a similar form factor to a dashboard screen (like a
+Nexus 7).</li>
+<li>Configure the device for Android development.</li>
+<li>Install the APK for the media client from the Android Auto SDK on the device.</li>
+<li>Install the APK for your app on the device.</li>
+<li>Open the media client app from the Android Auto SDK on the device.</li>
+<li>Select your app from the list of available services.</li>
+</ol>
+
+<p>The customized UI for your app appears on the client. You can navigate the content
+library and play media. If your app provides app-specific actions, these actions appear
+in the UI controls.</p>
+
+
+<h2 id="running" style="margin-top:30px">Running Your App on Android Auto</h2>
+
+<p>Media apps are available on the Google Play Store for compatible Android devices.
+When users connect their Android device to a compatible vehicle, the
+Android Auto media client shows a list of all the Android apps installed on the phone
+that implement the media service interfaces.</p>
+
+<p>When users select one of these apps, the Android Auto media client uses the app’s
+service to respond to user input and invoke the methods in the media service interfaces
+to build the UI, navigate the content library, and play media.</p>
+
+<div style="margin-bottom:40px"> </div>
+</div>
diff --git a/docs/html/design/design_toc.cs b/docs/html/design/design_toc.cs
index 4c2aab2..2bd0bf9 100644
--- a/docs/html/design/design_toc.cs
+++ b/docs/html/design/design_toc.cs
@@ -67,6 +67,25 @@
</li>
<li class="nav-section">
+ <div class="nav-section-header"><a href="<?cs var:toroot ?>design/devices.html">Devices</a></div>
+ <ul>
+ <!-- wear design goes here -->
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>design/tv/index.html">TV</a></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>design/tv/principles.html">Design Principles</a></li>
+ <li><a href="<?cs var:toroot ?>design/tv/ui-overview.html">UI Overview</a></li>
+ <li><a href="<?cs var:toroot ?>design/tv/style.html">Style</a></li>
+ <li><a href="<?cs var:toroot ?>design/tv/patterns.html">Patterns</a></li>
+ </ul>
+ </li>
+
+ </ul>
+ </li>
+
+
+ <li class="nav-section">
<div class="nav-section-header empty"><a href="<?cs var:toroot ?>design/downloads/index.html">Downloads</a></div>
</li>
diff --git a/docs/html/design/tv/images/apps-games-rows.png b/docs/html/design/tv/images/apps-games-rows.png
new file mode 100644
index 0000000..1724147
--- /dev/null
+++ b/docs/html/design/tv/images/apps-games-rows.png
Binary files differ
diff --git a/docs/html/design/tv/images/atv-home.png b/docs/html/design/tv/images/atv-home.png
new file mode 100644
index 0000000..2c18827
--- /dev/null
+++ b/docs/html/design/tv/images/atv-home.png
Binary files differ
diff --git a/docs/html/design/tv/images/atv.png b/docs/html/design/tv/images/atv.png
new file mode 100644
index 0000000..cd96164
--- /dev/null
+++ b/docs/html/design/tv/images/atv.png
Binary files differ
diff --git a/docs/html/design/tv/images/overscan.png b/docs/html/design/tv/images/overscan.png
new file mode 100644
index 0000000..bf08dd8
--- /dev/null
+++ b/docs/html/design/tv/images/overscan.png
Binary files differ
diff --git a/docs/html/design/tv/images/recommendations.png b/docs/html/design/tv/images/recommendations.png
new file mode 100644
index 0000000..579b390
--- /dev/null
+++ b/docs/html/design/tv/images/recommendations.png
Binary files differ
diff --git a/docs/html/design/tv/images/search.png b/docs/html/design/tv/images/search.png
new file mode 100644
index 0000000..be0d778
--- /dev/null
+++ b/docs/html/design/tv/images/search.png
Binary files differ
diff --git a/docs/html/design/tv/images/settings.png b/docs/html/design/tv/images/settings.png
new file mode 100644
index 0000000..f9f45fa
--- /dev/null
+++ b/docs/html/design/tv/images/settings.png
Binary files differ
diff --git a/docs/html/design/tv/index.jd b/docs/html/design/tv/index.jd
new file mode 100644
index 0000000..2519e25
--- /dev/null
+++ b/docs/html/design/tv/index.jd
@@ -0,0 +1,31 @@
+page.title=Design for TV
+header.justLinks=1
+footer.hide=1
+@jd:body
+
+<style>
+#landing-graphic-container {
+ position: relative;
+}
+
+#text-overlay {
+ position: absolute;
+ left: 0;
+ top: 402px;
+ width: 220px;
+}
+</style>
+
+<div id="landing-graphic-container">
+ <div id="text-overlay">
+ <span itemprop="description">
+ Build beautiful apps for the biggest screen in the house.</span>
+ <br><br>
+ <a href="{@docRoot}design/tv/principles.html"
+ class="landing-page-link">Design Principles</a>
+ </div>
+
+ <a href="{@docRoot}design/tv/principles.html">
+ <img src="{@docRoot}design/tv/images/atv.png" style="margin-left: 70px;">
+ </a>
+</div>
diff --git a/docs/html/design/tv/patterns.jd b/docs/html/design/tv/patterns.jd
new file mode 100644
index 0000000..c8cc0b0
--- /dev/null
+++ b/docs/html/design/tv/patterns.jd
@@ -0,0 +1,100 @@
+page.title=Patterns for TV
+page.tags="design"
+@jd:body
+
+<p>As a developer of apps for TV, you should follow certain patterns to enable users to
+ quickly understand and efficiently your app. This section describes recommended design patterns
+ for TV apps.</p>
+
+<h2>Navigation</h2>
+
+<p>Users typically navigate TV devices using a directional pad (D-Pad). This type of controller
+ limits movement to up, down, left, and right. In a typical D-Pad remote, hardware keys that
+ correspond to those directions are present and an additional action key is available to make a
+ selection. As you design your Android application for TVs, pay special attention to how users
+ navigate your application when using a remote control instead of a touchscreen.</p>
+
+<p>[add visual: D-Pad image or illustration]</p>
+
+<p>A key aspect of making your application work well with a D-Pad controller is to make sure
+ that there is always a object that is obviously in focus. If a user cannot see what is in focus,
+ they will not be able to navigate your app intuitively with this type of controller.</p>
+
+<p>Optimize your app screen layouts for D-Pad navigation. Align objects in your app lists and
+ grids to make navigation within each screen intuitive. Design your layout so it takes advantage of
+ two-axis navigation.</p>
+
+
+<h2>Home and Back Buttons</h2>
+
+<p>
+ In addition to the D-Pad buttons, Android TV devices always include Home and Back buttons on their
+ controllers. Make sure the Back button functions within your app in a way that is consistent with
+ the general <a href="{@docRoot}design/patterns/navigation.html">Android Design guidelines</a>.
+</p>
+
+
+<h2>Focus and Selection</h2>
+
+<p>Providing good focus and selection indicators is key to making your app useable on TV. As
+ mentioned previously, making sure that an object is always selected in your app is critical for
+ effective navigation using a D-Pad. This requirement also means that you must use focus indicators
+ that are easy to recognize and should be consistent throughout your app.</p>
+
+<p>
+ [add visual of selected item on screen]
+</p>
+
+<p>The default focus indicator used in Android TV use a combination of scale, shadow,
+ brightness, and opacity. The focus feedback is enhanced by displaying an animation going from a
+ non-focused to a focused state and back. Instead of immediately applying the focus transformation,
+ it is animated into place to reduce abrupt changes and help users notice how the object changed.</p>
+
+<h2>Audio Feedback</h2>
+
+<p>Sounds on Android TV bring a cinematic quality to the interaction experience. You should
+ consider adding sounds for user actions or to provide feedback when a user is only partially
+ visually engaged with the screen (e.g., because they have their hands full or are multitasking).
+ You should also consider using sounds as alternatives to error messages, for example to indicate
+ that a user has reached the end of a list or is trying to navigate to an undefined location.</p>
+
+<h2>Banners</h2>
+
+<p>
+ App Banners represent your app on the home screen of TV devices and serves and as a way for
+ users to launch your app. Here are specific requirements for the banner image:
+</p>
+
+<ul>
+ <li>Size: 320 x 180 px, xhdpi resource</li>
+ <li>Text should be included in the image. If your app is available in more than one
+ language, you must provide version of the banner image for each supported language.</li>
+</ul>
+
+
+<h2>App Icons</h2>
+
+<p>The app icon is shown in recommendation cards on the Home screen, search results and the main
+ Browse screen of your app if you use {@code BrowseFragment}. Here are the specific
+ requirements for the app icon:</p>
+
+<ul>
+ <li><p>Full color: size: 52x52dp, PNG</p></li>
+ <li><p>Monocolor: size 52x52dp, white(#fff) icon with transparent background, PNG</p></li>
+</ul>
+
+
+<h2>Background Images</h2>
+
+<p>Background images are displayed in the background of your app to provide additional visual
+ interest, information or branding. The BrowseFragment and DetailsFragment classes in the Leanback
+ support library provide specific support for background images and updating them as items are
+ brought into and out of focus. Here are the specific requirements for background images:</p>
+
+<ul>
+ <li>2016x1134 (1920x1080 + 5% extra margin for motion)</li>
+</ul>
+
+<p>
+ <strong>Note:</strong> If the image does not meet this requirement, it is scaled to fit.
+</p>
\ No newline at end of file
diff --git a/docs/html/design/tv/principles.jd b/docs/html/design/tv/principles.jd
new file mode 100644
index 0000000..5c0ce10
--- /dev/null
+++ b/docs/html/design/tv/principles.jd
@@ -0,0 +1,45 @@
+page.title=Design Principles for TV
+@jd:body
+
+<p>Users bring a specific set of expectations to the experience of watching TV, versus
+ interacting with a phone or tablet. These principles have been developed by the Android User
+ Experience Team to guide creation of the Android TV platform and the apps that run on it.</p>
+
+<h2>Casual Consumption</h2>
+
+<p>The TV is an entertainment interface, not a computer or mobile device. Optimize for
+ activities that put content at the center: from the casual posture of movie-watching, to
+ edge-of-seat, immersive gameplay, to hanging out with friends in a living room.</p>
+
+<p>Users expect immediate access to to content when they turn on a TV. Get users into the action
+ fast, be it the big game, their favorite show, or a game with friends. The next piece of content
+ to watch or play should only be a click or two away.</p>
+
+<p>
+ [add a visual]
+</p>
+
+
+<h2>Cinematic Experience</h2>
+
+<p>Create immersive experiences for the user. Design for as little user interface and as much
+ content as possible on each screen. Use visual imagery, movement and sound to inform and delight
+ users. Avoid using on-screen text to convey information and purpose. Tell your story with pictures
+ and sound.</p>
+
+<p>
+ [add a visual]
+</p>
+
+
+<h2>Simplicity</h2>
+
+<p>An Android TV should be simple and magical. It’s all about finding and enjoying content and
+ apps with the least amount of friction. Minimize the number of navigation steps required to
+ perform actions. Build apps with the fewest screens possible between app entry and content
+ immersion. Avoid making users enter text whenever possible, and use voice interfaces when you
+ require text input.</p>
+
+<p>
+ [add a visual]
+</p>
diff --git a/docs/html/design/tv/style.jd b/docs/html/design/tv/style.jd
new file mode 100644
index 0000000..479ed91
--- /dev/null
+++ b/docs/html/design/tv/style.jd
@@ -0,0 +1,108 @@
+page.title=Style for TV
+page.tags="design"
+@jd:body
+
+
+<p>Follow these style guidelines to create beautiful, functional apps for TV.</p>
+
+
+<h2>Layouts</h2>
+
+<p>The difference between a TV experience that feels right and one that does not greatly depends
+ on the number, spacing and size of on-screen elements. Although TV sizes and resolutions have
+ steadily increased over time, users expect TV experiences to be relatively simple and
+ uncluttered.</p>
+
+<p>The additional resolution and screen area afforded by modern displays is best used to display
+ things at better quality, rather than greater quantity. For example, use your layouts to show
+ large, beautiful pieces of content, or resize type for both easy reading and generous spacing.</p>
+
+<p>If you are creating an app for browsing and playing content, use the prebuilt fragments in the
+ Leanback support library. These layouts have been built specifically for use on TV devices with
+ the guidance of the Android User Experience team. For more information on using these classes,
+ see the <a href="{@docRoot}preview/tv/build-ui/index.html">User Interfaces</a> guide.
+</p>
+
+<p>Here are some additional recommendations for creating functional and attractive layout for TV
+ apps:</p>
+
+<ul>
+ <li><p>Build layouts designed for landscape orientation. TV screens always use in this
+ orientation.</p></li>
+ <li><p>Put on-screen navigational controls on the left or right side of the screen and
+ save the vertical space for content.</p></li>
+ <li><p>Create UIs that are divided into sections, by using Fragments and use view groups
+ like GridView instead of ListView to make better use of the horizontal screen space.</p></li>
+ <li><p>Add sufficient margins between layout controls to avoid a cluttered interface.</p></li>
+</ul>
+
+
+<h3>Screen Size</h3>
+
+<p>TV devices running Android are intended to operate at HD resolution (1920 x 1080 pixels) or
+ higher. Design your artwork assets for best viewing at this resolution.</p>
+
+
+<h3>Overscan</h3>
+
+<p>During the evolution of TV technology, overscan originally described an area of TV content
+ outside of a safe zone that most TVs could reliably display. Even on some of today’s HDTV flat
+ screens, areas outside that zone may not be visible.</p>
+
+<img src="{@docRoot}design/tv/images/overscan.png" alt="image alt text" />
+
+<p>Build a 10% margin into your TV screen designs to account for overscan area the TV may not
+ display correctly. On a 1920 x 1080 pixel screen, this margin should be a minimum of 27px from the
+ top and bottom edges and a minimum of 48px from the right and left edges of the picture.</p>
+
+
+<h2>Color</h2>
+
+<p>Color rendering on televisions can be imprecise compared to computer monitors or mobile
+ devices. LCD and Plasma TVs often apply smoothing and sharpening filters, and color rendering may
+ not match what you see on a computer screen.</p>
+
+<p>Subtle hue or brightness differences between elements may disappear or be over-emphasized on
+ TV screens. Some color gradient combinations will show bands. You should avoid pure whites and
+ highly saturated colors in large areas of the screen (especially reds, greens and blues). You
+ should also avoid using very dark or muddy colors, as TV settings may display these colors with
+ exaggerated contrast, causing them to be indistinguishable.</p>
+
+
+<h2>Typography</h2>
+
+<p>The text and controls in a TV application's UI should be easily visible and navigable from a
+ distance. The minimum recommended font size for TV is 12sp. The default text size setting should
+ be 18sp. We recommend the following guidelines for TV apps:</p>
+
+<ul>
+ <li>Browse Titles: Regular 44sp</li>
+ <li>Browse Menu Category Text: 20sp at 50% transparency</li>
+ <li>Browse Focused Menu Category Text: 24sp with no transparency</li>
+ <li>Row Category Titles focused: 20sp with no transparency</li>
+ <li>Row Category Titles focused: 20sp at 50% transparency</li>
+ <li>Details Content Titles: 34sp</li>
+ <li>Details Subtext: 14sp</li>
+</ul>
+
+<p>[visual showing text on a TV screen (sidebar position)]</p>
+
+<p>Some TVs have strong sharpness and contrast settings as their defaults. These picture
+ settings make thin and light typefaces look jagged and make the text difficult for people to read.
+ Therefore you should avoid thin or light typefaces on TV.</p>
+
+<h2>Text</h2>
+
+<p>Use text in TV apps sparingly. The position of users relative to a TV screen
+ (typically about 10 away) makes it harder for users to read text and the expectation of users in a
+ TV environment not conducive to reading. Follow these tips for the best handling of text in your
+ app:</p>
+
+<ul>
+ <li>Break text into small chunks that users can quickly scan.</li>
+ <li>Use light text on a dark background. This style is easier to read on a TV.</li>
+ <li>Avoid lightweight fonts or fonts that have both very narrow and very broad
+ strokes. Use simple sans-serif fonts and use anti-aliasing to increase readability.</li>
+ <li>Use layout-relative sizing rather than absolute sizing and density-independent
+ pixel units instead of absolute pixel units.</li>
+</ul>
\ No newline at end of file
diff --git a/docs/html/design/tv/ui-overview.jd b/docs/html/design/tv/ui-overview.jd
new file mode 100644
index 0000000..c58c9cd
--- /dev/null
+++ b/docs/html/design/tv/ui-overview.jd
@@ -0,0 +1,63 @@
+page.title=UI Overview for TV
+page.tags="design"
+@jd:body
+
+<p>The Android TV system user interface provides the launch pad for your app's big screen
+ experience. It's important to understand how your app is presented in the main user interface and
+ how your app can help users get to the content they want quickly, including contributing content
+ suggestions to the recommendations row.</p>
+
+<p>This section provides quick overview of the Android TV user interface.</p>
+
+
+<h2>Home Screen</h2>
+
+<p>The Home Screen is the start of a TV user's experience, providing search, content
+ recommendations, access to apps and settings. The Home Screen provides a rich and cinematic
+ overview of apps and content.</p>
+
+<img src="{@docRoot}design/tv/images/atv-home.png" alt="TV Home screen" />
+
+
+<h2>Search</h2>
+
+<p>By bringing the power of Google search to the big screen, Android TV makes new, dynamic
+ connections between content - a favorite movie may connect to the discovery of a new music artist,
+ planning trip to Paris might surface new YouTube content and photos.</p>
+
+<img src="{@docRoot}design/tv/images/search.png" alt="Recommendations Row" />
+
+
+<h2>Recommendations</h2>
+
+<p>The recommendation row on Android TV is a central feature of the Home Screen that allows
+ users quick access to dynamic and relevant content for their media consumption activities. The
+ stream is optimized for quick browsing of personalized content and activity resumption (on the
+ device and across devices), while also providing a way for users to act on meaningful new content.</p>
+
+<img src="{@docRoot}design/tv/images/recommendations.png" alt="Recommendations Row" />
+
+<p>
+ The recommendations are based on the user’s recent and frequent usage behaviors, as well as
+ expressed content preferences. They are presented as cards that represent a system or app action,
+ notification, activity, or piece of actionable media. Your app can provide suggestions for the
+ recommendations row to help get your content noticed. To learn more, see
+ <a href="{@docRoot}preview/tv/build-ui/recommendations.html">Recommendations</a>.
+</p>
+
+
+<h2>Apps and Games</h2>
+
+<p>Apps and Games rows both have special areas on the Home Screen. Within these respective
+ areas, Apps and Games titles are reordered to reflect the user’s recent usage.</p>
+
+<img src="{@docRoot}design/tv/images/apps-games-rows.png" alt="Apps and Games Rows" />
+
+
+<h2>Settings</h2>
+
+<p>Access to Settings is found at the bottom of the Home Screen. From here, the user can access
+ Android and device-specific settings. Please see the "Settings" section for more detailed
+ information.</p>
+
+<img src="{@docRoot}design/tv/images/settings.png" alt="Settings Row" />
diff --git a/docs/html/distribute/engage/analytics.jd b/docs/html/distribute/engage/analytics.jd
new file mode 100644
index 0000000..5f7cade
--- /dev/null
+++ b/docs/html/distribute/engage/analytics.jd
@@ -0,0 +1,50 @@
+page.title=Understand User Behavior
+page.metaDescription=Use Google Analytics to learn what your users like and what keeps them coming back.
+page.tags="analytics, user behavior"
+page.image=/images/gp-analytics.jpg
+
+@jd:body
+
+<div class="figure">
+ <img src="{@docRoot}images/gp-analytics.jpg" style="width:320px">
+</div>
+
+
+<p>
+ Link your Google Play Developer Console with Google Analytics to learn much
+ more about how users interact with your app — before and after they
+ download it.
+</p>
+
+<p>
+ Start by discovering how many people visit your Google Play listing page,
+ where they come from, and how many go on to install your app. Once the app is
+ launched, use Google Analytics to see which of your features are most
+ popular, where power users spend their time, who tends to make in-app
+ purchases, and more.
+</p>
+
+<p>
+ Google Analytics delivers the numbers in real time, so you can act fast to
+ update your landing page and your app. <a href=
+ "http://www.google.com/analytics/mobile/">Learn more</a>.
+</p>
+
+<p>
+ If you have a Google Analytics account already, linking it to Google Play
+ takes just a few moments. You can also link your Google Analytics account to
+ Admob to start gaining more user insights to improve your in-app marketing.
+</p>
+
+ <div class="headerLine clearfloat">
+ <h2 id="related-resources">
+ Related Resources
+ </h2>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/engage/analytics"
+ data-sortorder="-timestamp"
+ data-cardsizes="9x3"
+ data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/deep-linking.jd b/docs/html/distribute/engage/deep-linking.jd
index 0417ba1..a25c3c6 100644
--- a/docs/html/distribute/engage/deep-linking.jd
+++ b/docs/html/distribute/engage/deep-linking.jd
@@ -1,13 +1,13 @@
page.title=Deep Link to Bring Users Back
-page.metaDescription=Use deep links to bring your users into your apps from social posts or search.
+page.metaDescription=Use deep links to bring your users into your apps from social posts, search, or ads.
page.tags="app indexing, google+ signin"
page.image=/images/gp-listing-4.jpg
@jd:body
<p>
- Use deep links to bring your users into your apps from social posts or
- search.
+ Use deep links to bring your users into your apps from social posts,
+ search, or ads.
</p>
<div class="headerLine">
@@ -47,6 +47,11 @@
<h2>Deep Linking from Google Search — App Indexing</h2>
</div>
+
+<div style="float:right;">
+ <img src="/images/gp-listing-4.jpg" style="padding-top:1em;padding-left:2em;">
+</div>
+
<p>
Another way to bring users back to your apps is to apply for app indexing.
</p>
@@ -60,11 +65,29 @@
content</a>.
</p>
-<div>
- <img src="{@docRoot}images/gp-listing-4.jpg" style="padding-top:1em;">
+<div class="clearfloat" style="margin-top:2em;"></div>
+
+<div style="float:right;width:340px;padding-left:2em;">
+ <img src="/images/gp-ads-linking2.jpg" style="padding-top:1em;">
</div>
-<div class="headerLine">
+<div class="headerLine ">
+<h2>Deep Linking from Google Ads</h2>
+</div>
+<p>
+ Ads can remind users about the apps they already have.
+</p>
+
+<p>
+ As with deep links from Google's organic search results, AdWords deep links
+ send users directly to the relevant pages in apps they already have on their
+ mobile device. A mobile search for "flights to London," for instance, could
+ take a user straight to the London page in a travel app. <a href=
+ "http://www.thinkwithgoogle.com/products/ads-apps.html"
+ class="external-link">Learn more</a>.
+</p>
+
+<div class="headerLine clearfloat">
<h2 id="related-resources">
Related Resources
</h2>
diff --git a/docs/html/distribute/engage/engage_toc.cs b/docs/html/distribute/engage/engage_toc.cs
index 0314f8c..596051a 100644
--- a/docs/html/distribute/engage/engage_toc.cs
+++ b/docs/html/distribute/engage/engage_toc.cs
@@ -37,6 +37,12 @@
</li>
<li class="nav-section">
<div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+ var:toroot?>distribute/engage/analytics.html">
+ <span class="en">Understand User Behavior</span></a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
var:toroot?>distribute/engage/app-updates.html">
<span class="en">Update Regularly</span></a>
</div>
diff --git a/docs/html/distribute/engage/index.jd b/docs/html/distribute/engage/index.jd
index f8cd1ee..2b103c3 100644
--- a/docs/html/distribute/engage/index.jd
+++ b/docs/html/distribute/engage/index.jd
@@ -15,8 +15,8 @@
<div class="resource-widget resource-flow-layout landing col-16"
data-query="collection:distribute/engagelanding"
- data-cardSizes="6x6"
- data-maxResults="9">
+ data-cardSizes="9x6,9x6,6x6,6x6,6x6,9x6,9x6,6x6,6x6,6x6"
+ data-maxResults="10">
</div>
<h3>Related Resources</h3>
diff --git a/docs/html/distribute/engage/widgets.jd b/docs/html/distribute/engage/widgets.jd
index 286adea..6adb55c 100644
--- a/docs/html/distribute/engage/widgets.jd
+++ b/docs/html/distribute/engage/widgets.jd
@@ -1,5 +1,5 @@
page.title=Build Useful Widgets
-page.metaDescription=Use widgets to remind users about important information in your apps and games, even when your apps are closed.
+page.metaDescription=Use home screen widgets to remind users about important information in your apps and games, even when your apps are closed.
page.tags=""
page.image=/images/gp-engage-0.jpg
diff --git a/docs/html/distribute/monetize/ads.jd b/docs/html/distribute/monetize/ads.jd
index bcb1e52..9a847ff 100644
--- a/docs/html/distribute/monetize/ads.jd
+++ b/docs/html/distribute/monetize/ads.jd
@@ -10,17 +10,32 @@
</div>
<p>
- In-app advertising offers a quick and easy way to incorporate a monetization
- option into both your <a href=
+ Ads can be a quick and easy way to earn more from your <a href=
"{@docRoot}distribute/monetize/freemium.html">freemium</a>, <a href=
"{@docRoot}distribute/monetize/premium.html">premium</a>, and <a href=
- "{@docRoot}distribute/monetize/subscriptions.html">subscription</a> apps. </p>
+ "{@docRoot}distribute/monetize/subscriptions.html">subscription</a> apps.
+ AdMob and the Google Mobile Ads SDK let you add advertising to your apps with
+ just a few lines of code.
+</p>
-<p>Using <a href=
+<p>
+ The question is: which model gets the best results for your app? Google's ad
+ tools are made to help you figure out what combination works best for both
+ your audience and your bottom line. </p>
+
+<p>Start by linking your AdMob and Google
+ Analytics accounts to get better insights and more earning power: for
+ instance, AdMob can promote in-app purchases to the people who buy them most
+ often, while showing income-generating ads to those less likely to buy right
+ now.
+</p>
+
+<p>
+ Using <a href=
"http://www.google.com/ads/admob/monetize.html#subid=us-en-et-dac">AdMob</a>
- and the <a href="{@docRoot}google/play-services/ads.html">Google
- Mobile Ads SDK</a> included in Google Play Services, you’re able to add
- advertising into your apps, with just a few lines of code.
+ and the <a href="{@docRoot}google/play-services/ads.html">Google Mobile Ads
+ SDK</a> included in Google Play Services, you’re able to add advertising into
+ your apps, with just a few lines of code.
</p>
<p>
@@ -30,36 +45,33 @@
<ul>
<li>
<p>
- <strong>Placement within your apps</strong> — Well placed ads will
- optimize your revenue by making it more likely that users will ‘click
- through’. Poorly placed ads can result in low click-through rates, and in
- the worse cases poor rating and users rapidly abandoning your apps. You
- can get advice on how to best place ads from the developer training on
- <a href=
- "{@docRoot}training/monetization/ads-and-ux.html">using
- ads</a>.
+ <strong>Placement within your apps</strong> — Well-placed ads make
+ it more likely that users will click through and convert. Poorly-placed
+ ads lead to lower click-through rates, and even poor ratings and users
+ abandoning your apps. Our <a href=
+ "{@docRoot}training/monetization/ads-and-ux.html">developer training</a>
+ on using ads shows some of the best ways to place ads.
</p>
</li>
<li>
<p>
<strong>Ad formats</strong> — Every app offers a different type of
- experience for users, so it’s important to consider the format of ads
- you’re using to ensure it’s compatible with the experience. While banner
- ads may work well for a flashlight utility app, an immersive gaming app
- may benefit more from a video interstitial. Mismatched ad formats may
- negatively affect your users’ experience and ad revenue, so try to select
- formats that fit well with the content and flow of your apps.
+ experience for users, so it’s important that your ad formats match that
+ experience. While banner ads may work well for a flashlight utility app,
+ an immersive gaming app may benefit more from a video interstitial.
+ Mismatched ad formats can make users unhappy and leave money on the
+ table.
</p>
</li>
<li>
<p>
- <strong>Maximizing your performance</strong> — Ensure you’re optimizing
- your advertising revenue by maximizing your CPMs <em>and</em> fill rate.
- Often ad providers will cite very high CPMs but will have a low fill rate
- that can severely decrease your effective CPM, so look at both of these
- figures. Also consider using a <a href=
+ <strong>Maximizing your performance</strong> — Make sure you’re
+ optimizing your advertising revenue by maximizing your CPMs and fill
+ rate. Ad providers often cite their very high CPMs but don't mention low
+ fill rates that can severely decrease your effective CPM. Be sure to look
+ at both of these figures. Consider using a <a href=
"https://support.google.com/admob/v2/answer/3063564?hl=en&ref_topic=3063091#subid=us-en-et-dac">
mediation</a> solution if you’d like to use multiple ad providers in your
apps. Look for solutions that offer yield management or <a href=
@@ -71,30 +83,43 @@
<li>
<p>
- <strong>Exercising control options</strong> — A variety of ads promoting a
- broad selection of other services or apps may show up within you apps.
- Depending on your goals and the type of experience you want to provide
- your users, it may make sense to <a href=
+ <strong>Exercising control options</strong> — A variety of ads may
+ show up within your app. It may make sense to <a href=
"https://support.google.com/admob/v2/answer/3150235?hl=enl#subid=us-en-et-dac">
- block</a> certain advertisements from appearing. Some developers don’t
- want apps in a similar category showing to their users, but some don’t
- mind.
+ block</a> certain of those advertisements from appearing, depending on
+ your goals and the type of experience you want to provide. Some
+ developers, for instance, don’t want ads for apps in their same category
+ showing to their users, while others don’t mind at all.
</p>
</li>
<li>
<p>
- <strong>Cross promoting your other apps</strong> — Ads can be used for
- more than just earning revenue. Consider using <a href=
+ <strong>Cross promoting your other apps</strong> — Ads can do more
+ than earn revenue. Consider running <a href=
"https://support.google.com/admob/v2/answer/3210452?hl=en#subid=us-en-et-dac">
- house ads</a> within your apps to create awareness and promote your
- entire portfolio of apps. When launching new apps, an easy way to quickly
- attract users is to promote directly to your existing customers.
+ house ads</a> within your apps to promote other apps in your portfolio.
+ When you launch a new app, this kind of promotion is a free and easy way
+ to attract new users quickly.
</p>
</li>
</ul>
<p>
+ Don't forget that paid channels like AdWords and YouTube can help you cast a
+ wider net by reaching targeted audiences outside the app ecosystem. They're a
+ great way to find new users at a price that you control. <a href=
+ "https://support.google.com/adwords/answer/2549053">Learn more</a>.
+</p>
+
+<p>
+ To start monetizing with ads, sign up for AdMob and integrate the Google
+ Mobile Ads SDK into your apps. If you also need to manage direct deals with
+ advertisers, consider using DoubleClick for Publishers Small Business.
+</p>
+
+
+<p>
To start monetizing with ads sign up for <a href=
"http://www.google.com/ads/admob/#subid=us-en-et-dac">AdMob</a> and integrate
the <a href="https://developers.google.com/mobile-ads-sdk/download">Google
diff --git a/docs/html/distribute/users/index.jd b/docs/html/distribute/users/index.jd
index 77ef609..a810f36 100644
--- a/docs/html/distribute/users/index.jd
+++ b/docs/html/distribute/users/index.jd
@@ -14,8 +14,8 @@
<div class="resource-widget resource-flow-layout landing col-16"
data-query="collection:distribute/users"
- data-cardSizes="6x6, 6x6, 6x6, 9x6, 9x6, 6x6, 6x6, 6x6"
- data-maxResults="8">
+ data-cardSizes="6x6"
+ data-maxResults="6">
</div>
<h3>Related resources</h3>
diff --git a/docs/html/distribute/users/promote-with-ads.jd b/docs/html/distribute/users/promote-with-ads.jd
new file mode 100644
index 0000000..1e28ae1
--- /dev/null
+++ b/docs/html/distribute/users/promote-with-ads.jd
@@ -0,0 +1,45 @@
+page.title=Promote Your App with Ads
+page.metaDescription=Promote your app through AdMob, AdWords, and YouTube to find new users at the right moment.
+page.image=/images/gp-ads-console.jpg
+page.tags="users, ads, analytics"
+
+@jd:body
+
+<p>
+ AdMob is Google's advertising platform for mobile apps. You can use it to
+ monetize your app and promote your apps, and you can link your Google
+ Analytics account to AdMob so you can analyze your apps — all in one
+ place.
+</p>
+
+<p>
+ <a href="http://www.google.com/ads/admob/">AdMob</a> is the largest mobile ad
+ app network. But you get more than just massive scale: AdMob will soon help
+ you find the right users in related apps. If your app is for bicycling, AdMob
+ can promote your app on other fitness and cycling-related apps worldwide.
+ <a href=
+ "https://apps.admob.com/admob/signup?subid=us-en-et-dac&_adc=ww-ww-et-admob2&hl=en">
+ Sign up for AdMob</a>.
+</p>
+
+<p>
+ AdMob also offers new solutions to help you achieve app-related goals such as
+ downloads, re-engagement and in-app purchases using Google search and the
+ Google Display Network. These solutions include streamlined campaign creation
+ flows and tools to track performance across the entire app lifecycle.
+ <a href="https://support.google.com/adwords/answer/2549053?hl=en">Learn
+ More</a>.
+</p>
+<div style="margin-top:2em;">
+ <img src="{@docRoot}images/gp-ads-console.jpg">
+</div>
+
+<div class="headerLine">
+<h2 id="related-resources">Related Resources</h2>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/users/promotewithads"
+ data-sortOrder="-timestamp"
+ data-cardSizes="9x3"
+ data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/users/users_toc.cs b/docs/html/distribute/users/users_toc.cs
index a2437a6..1f173cb 100644
--- a/docs/html/distribute/users/users_toc.cs
+++ b/docs/html/distribute/users/users_toc.cs
@@ -28,7 +28,12 @@
</a>
</div>
</li>
-
+ <li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/promote-with-ads.html">
+ <span class="en">Promote with Ads</span>
+ </a>
+ </div>
+ </li>
</ul>
diff --git a/docs/html/google/auth/api-client.jd b/docs/html/google/auth/api-client.jd
index 402a95f..5331d1e 100644
--- a/docs/html/google/auth/api-client.jd
+++ b/docs/html/google/auth/api-client.jd
@@ -1,4 +1,4 @@
-page.title=Accessing Google Play Services APIs
+page.title=Accessing Google APIs
page.tags="oauth 2.0","GoogleAuthUtil"
trainingnavtop=true
diff --git a/docs/html/google/google_toc.cs b/docs/html/google/google_toc.cs
index 6ff00c0..b4028bd 100644
--- a/docs/html/google/google_toc.cs
+++ b/docs/html/google/google_toc.cs
@@ -3,11 +3,11 @@
######## ATTENTION ###############
######## ###############
#########################################################
-
+
IF YOU MAKE CHANGES TO THIS FILE, YOU MUST GENERATE THE
GMS REFERENCE DOCS, BECAUSE THEY ARE NOT INCLUDED IN THE
DOCS BUILD RULE.
-
+
#########################################################
#########################################################
?>
@@ -73,11 +73,11 @@
</div>
<ul>
<li><a href="<?cs var:toroot?>google/play-services/setup.html">
- <span class="en">Setup</span></a>
+ <span class="en">Setting Up Google Play Services</span></a>
</li>
<li class="nav-section">
<div class="nav-section-header"><a href="<?cs var:toroot?>google/auth/api-client.html">
- <span class="en">Accessing Google Play Services APIs</span></a>
+ <span class="en">Accessing Google APIs</span></a>
</div>
<ul>
<li>
diff --git a/docs/html/google/play-services/setup.jd b/docs/html/google/play-services/setup.jd
index 744e191..4332953 100644
--- a/docs/html/google/play-services/setup.jd
+++ b/docs/html/google/play-services/setup.jd
@@ -1,4 +1,4 @@
-page.title=Set Up Google Play Services SDK
+page.title=Setting Up Google Play Services
@jd:body
@@ -8,8 +8,7 @@
<h2>In this document</h2>
<ol>
- <li><a href="#Install">Install the Google Play Services SDK</a></li>
- <li><a href="#Setup">Set Up a Project that Uses Google Play Services</a></li>
+ <li><a href="#Setup">Add Google Play Services to Your Project</a></li>
<li><a href="#Proguard">Create a Proguard Exception</a></li>
<li><a href="#ensure">Ensure Devices Have the Google Play services APK</a></li>
</ol>
@@ -18,12 +17,17 @@
</div>
</div>
+<script>
+$(document).ready(function() {
+ setupIdeDocToggle();
+});
+</script>
-
+
<p>To develop an app using the <a href="{@docRoot}reference/gms-packages.html">Google
-Play services APIs</a>, you must download the Google Play services SDK
-from the <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.
-The download includes the client library and code samples.</p>
+Play services APIs</a>, you need to set up your project with the Google Play services SDK.
+<p>If you haven't installed the Google Play services SDK yet, go get it now by following the guide
+to <a href="{@docRoot}sdk/installing/adding-packages.html">Adding SDK Packages</a>.</p>
<p>To test your app when using the Google Play services SDK, you must use either:</p>
<ul>
@@ -33,68 +37,25 @@
that runs the Google APIs platform based on Android 4.2.2 or higher.</li>
</ul>
-<p>Ideally, you should develop and test your app on a variety of devices, including
-both phones and tablets.</p>
-<h2 id="Install">Install the Google Play Services SDK</h2>
+<h2 id="Setup">Add Google Play Services to Your Project</h2>
-<p>To install the Google Play services SDK for development:</p>
+<p>
+<select class="ide">
+ <option value="eclipse">Using Eclipse with ADT</option>
+ <option value="studio">Using Android Studio</option>
+ <option value="other">Using something else</option>
+</select>
+</p>
+
+
+<div class="select-ide studio">
<ol>
- <li>Launch the SDK Manager in one of the following ways:
- <ul>
- <li>In Android Studio, click <strong>SDK Manager</strong>
-<img src="{@docRoot}images/tools/sdk-manager-studio.png" style="vertical-align:bottom;margin:0;height:19px" />
-in the toolbar.</li>
- <li>In Eclipse (with <a href="{@docRoot}tools/help/adt.html">ADT</a>),
- select <strong>Window</strong> > <strong>Android SDK Manager</strong>.</li>
- <li>On Windows, double-click the <code>SDK Manager.exe</code> file at the root of the Android
- SDK directory.</li>
- <li>On Mac or Linux, open a terminal and navigate to the <code>tools/</code> directory in the
- Android SDK, then execute <code>android sdk</code>.</li>
- </ul>
- </li>
- <li>Install the Google Play services SDK.
- <p>Scroll to the bottom of the package list, expand <b>Extras</b>, select
- <b>Google Play services</b>, and install it. If you're using Android Studio, also install
- <b>Google Repository</b> (it provides the Maven repository used for Gradle builds).</p>
- <p>The Google Play services SDK is saved in your Android SDK environment at
- <code><android-sdk>/extras/google/google_play_services/</code>.</p>
-
-<p class="note"><strong>Note:</strong> Google Play services 4.0.30 (released
-November 2013) and newer versions require Android 2.3 or higher. If your app supports Android 2.2,
-you can continue development with the Google Play services SDK, but must instead install
-<b>Google Play services for Froyo</b> from the SDK Manager.</p>
-
- </li>
- <li>Install a compatible version of the Google APIs platform.
- <p>If you want to test your app on the emulator, expand the directory for <b>Android 4.2.2
- (API 17)</b> or a higher version, select <b>Google APIs</b>, and install it. Then create a
- new <a href="{@docRoot}tools/devices/index.html">AVD</a> with Google APIs as
- the platform target.</p>
- </li>
- <li>Make a copy of the Google Play services library project.
- <p class="note"><strong>Note:</strong> If you are using Android Studio, skip this step.</p>
- <p>Copy the library project at
- <code><android-sdk>/extras/google/google_play_services/libproject/google-play-services_lib/</code>
- to the location where you maintain your Android app projects.
- <p>If you are using Eclipse, import the library project into your workspace.
- Click <b>File > Import</b>, select <b>Android > Existing
- Android Code into Workspace</b>, and browse to the copy of the library project to import it.</p>
- </li>
-</ol>
-
-
-
-<h2 id="Setup">Set Up a Project that Uses Google Play Services</h2>
-
-<p><b>Using Android Studio:</b></p>
-
-<ol>
- <li>Open the <code>build.gradle</code> file inside your application module directory.
- <p class="note"><strong>Note:</strong> Android Studio projects contain a top-level
- <code>build.gradle</code> file and a <code>build.gradle</code> file for each module.
+ <li>Open the <code>build.gradle</code> file inside your application module directory.
+ <p class="note"><strong>Note:</strong> Android Studio projects contain a top-level
+ <code>build.gradle</code> file and a <code>build.gradle</code> file for each module.
Be sure to edit the file for your application module. See
<a href="{@docRoot}sdk/installing/studio-build.html">Building Your Project with
Gradle</a> for more information about Gradle.</p></li>
@@ -128,8 +89,11 @@
<p>You can now begin developing features with the
<a href="{@docRoot}reference/gms-packages.html">Google Play services APIs</a>.</p>
+</div><!-- end studio -->
-<p><b>Using Eclipse or another IDE:</b></p>
+
+
+<div class="select-ide eclipse other">
<p>To make the Google Play services APIs available to your app, you must reference the library
project you created in step 4 of the <a href="#Install">installation instructions</a>.</p>
@@ -156,6 +120,9 @@
you can begin developing features with the
<a href="{@docRoot}reference/gms-packages.html">Google Play services APIs</a>.</p>
+</div><!-- end eclipse and other -->
+
+
<h2 id="Proguard">Create a Proguard Exception</h2>
@@ -236,5 +203,6 @@
that takes the user to Google Play Store to install the update.</p>
-<p>To then begin a connection to Google Play services, read <a
-href="{@docRoot}google/auth/api-client.html">Accessing Google Play Services APIs</a>.</p>
+<p>To then begin a connection to Google Play services (required by most Google APIs such
+as Google Drive, Google+, and Games), read <a
+href="{@docRoot}google/auth/api-client.html">Accessing Google APIs</a>.</p>
diff --git a/docs/html/guide/components/activities.jd b/docs/html/guide/components/activities.jd
index b4617fb..5e6917b 100644
--- a/docs/html/guide/components/activities.jd
+++ b/docs/html/guide/components/activities.jd
@@ -4,12 +4,6 @@
<div id="qv-wrapper">
<div id="qv">
-<h2>Quickview</h2>
-<ul>
- <li>An activity provides a user interface for a single screen in your application</li>
- <li>Activities can move into the background and then be resumed with their state restored</li>
-</ul>
-
<h2>In this document</h2>
<ol>
<li><a href="#Creating">Creating an Activity</a>
diff --git a/docs/html/guide/components/bound-services.jd b/docs/html/guide/components/bound-services.jd
index 653c7a0..4215f0f2 100644
--- a/docs/html/guide/components/bound-services.jd
+++ b/docs/html/guide/components/bound-services.jd
@@ -6,12 +6,6 @@
<div id="qv-wrapper">
<ol id="qv">
-<h2>Quickview</h2>
-<ul>
- <li>A bound service allows other components to bind to it, in order to interact with it and
-perform interprocess communication</li>
- <li>A bound service is destroyed once all clients unbind, unless the service was also started</li>
-</ul>
<h2>In this document</h2>
<ol>
<li><a href="#Basics">The Basics</a></li>
diff --git a/docs/html/guide/components/fragments.jd b/docs/html/guide/components/fragments.jd
index 32c9f99..0cc5f72 100644
--- a/docs/html/guide/components/fragments.jd
+++ b/docs/html/guide/components/fragments.jd
@@ -5,15 +5,6 @@
<div id="qv-wrapper">
<div id="qv">
-
- <h2>Quickview</h2>
- <ul>
- <li>Fragments decompose application functionality and UI into reusable modules</li>
- <li>Add multiple fragments to a screen to avoid switching activities</li>
- <li>Fragments have their own lifecycle, state, and back stack</li>
- <li>Fragments require API Level 11 or greater</li>
- </ul>
-
<h2>In this document</h2>
<ol>
<li><a href="#Design">Design Philosophy</a></li>
diff --git a/docs/html/guide/components/processes-and-threads.jd b/docs/html/guide/components/processes-and-threads.jd
index c8c3764..e7ef7ba 100644
--- a/docs/html/guide/components/processes-and-threads.jd
+++ b/docs/html/guide/components/processes-and-threads.jd
@@ -5,13 +5,6 @@
<div id="qv-wrapper">
<div id="qv">
-<h2>Quickview</h2>
-<ul>
- <li>Every application runs in its own process and all components of the application run in that
-process, by default</li>
- <li>Any slow, blocking operations in an activity should be done in a new thread, to avoid slowing
-down the user interface</li>
-</ul>
<h2>In this document</h2>
<ol>
diff --git a/docs/html/guide/components/services.jd b/docs/html/guide/components/services.jd
index da01d2c..6e22be8 100644
--- a/docs/html/guide/components/services.jd
+++ b/docs/html/guide/components/services.jd
@@ -3,14 +3,6 @@
<div id="qv-wrapper">
<ol id="qv">
-<h2>Quickview</h2>
-<ul>
- <li>A service can run in the background to perform work even while the user is in a different
-application</li>
- <li>A service can allow other components to bind to it, in order to interact with it and
-perform interprocess communication</li>
- <li>A service runs in the main thread of the application that hosts it, by default</li>
-</ul>
<h2>In this document</h2>
<ol>
<li><a href="#Basics">The Basics</a></li>
diff --git a/docs/html/guide/components/tasks-and-back-stack.jd b/docs/html/guide/components/tasks-and-back-stack.jd
index f818873..e054313 100644
--- a/docs/html/guide/components/tasks-and-back-stack.jd
+++ b/docs/html/guide/components/tasks-and-back-stack.jd
@@ -5,14 +5,6 @@
<div id="qv-wrapper">
<div id="qv">
-<h2>Quickview</h2>
-<ul>
- <li>All activities belong to a task</li>
- <li>A task contains a collection of activities in the order in which the user interacts with
-them</li>
- <li>Tasks can move to the background and retain the state of each activity in order for users
-to perform other tasks without losing their work</li>
-</ul>
<h2>In this document</h2>
<ol>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 0a234aa..ff08312 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -564,7 +564,11 @@
<li><a href="<?cs var:toroot ?>guide/practices/tablets-and-handsets.html">
<span class="en">Supporting Tablets and Handsets</span>
</a></li>
-
+ <li>
+ <a href="<?cs var:toroot ?>guide/practices/verifying-apps-art.html">
+ <span class="en">Verifying App Behavior on ART</span>
+ </a>
+ </li>
</ul>
</li>
diff --git a/docs/html/guide/practices/verifying-apps-art.jd b/docs/html/guide/practices/verifying-apps-art.jd
new file mode 100644
index 0000000..0eedfaf
--- /dev/null
+++ b/docs/html/guide/practices/verifying-apps-art.jd
@@ -0,0 +1,296 @@
+page.title=Verifying App Behavior on the Android Runtime (ART)
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>Quickview</h2>
+ <ul>
+ <li>The new Android runtime (ART) is available on some of the newest Android
+ devices, though all of them currently have Dalvik as the default
+ runtime.</li>
+ <li>App developers should make sure their apps are compatible with ART,
+ especially if you use JNI to run native code or if you use certain tools
+ that produce non-standard code (such as some obfuscators).</li>
+ </ul>
+
+ <h2 id="Contents">In this document</h2>
+ <ol>
+ <li><a href="#GC_Migration">Addressing Garbage Collection (GC) Issues</a></li>
+ <li><a href="#JNI_Issues">Preventing JNI Issues</a>
+ <ol>
+ <li><a href="#JNI_and_GC">Checking JNI code for garbage-collection
+ issues</a></li>
+ <li><a href="#Error_Handling">Error handling</a></li>
+ <li><a href="#Object_Model_Changes">Object model changes</a></li>
+ </ol>
+ </li>
+ <li><a href="#Stack_Size">Preventing Stack Size Issues</a></li>
+ <li><a href="#AOT_Fails">Fixing AOT Compilation Issues</a></li>
+ <li><a href="#Reporting_Problems">Reporting Problems</a></li>
+ </ol>
+ <h2>See also</h2>
+ <ol>
+ <li><a href="http://source.android.com/devices/tech/dalvik/art.html">Introducing ART</a></li>
+ <li><a
+href="http://android-developers.blogspot.com/2011/07/debugging-android-jni-with-checkjni.html">Debugging
+Android JNI with CheckJNI</a></li>
+ </ol>
+</div>
+</div>
+
+<p>With Android 4.4, we are beginning to roll out a new Android runtime,
+<strong>ART</strong>. This runtime offers a number of new features that improve
+performance and smoothness of the Android platform and apps. (You can find more
+information about ART's new features in <a
+href="http://source.android.com/devices/tech/dalvik/art.html">Introducing
+ART</a>.)</p>
+
+<p>Currently, ART is available on a number of Android 4.4 devices, such as the
+Nexus 4, Nexus 5, Nexus 7, and Google Play edition devices.
+At this time, all devices still use Dalvik as the default runtime. We encourage
+you to test your apps for ART compatibility and to take advantage of ART's new
+features. However, for the time being, you should also take care to maintain
+compatibility with Dalvik.</p>
+
+<p>This document lets you know about things to watch for when migrating an
+existing app to be compatible with ART. Most apps should just work when
+running with ART. However, some techniques that work on Dalvik do not work on
+ART. This document discusses some of these issues.</p>
+
+<h2 id="GC_Migration">Addressing Garbage Collection (GC) Issues</h2>
+
+<p>Under Dalvik, apps frequently find it useful to explicitly call {@link
+java.lang.System#gc() System.gc()} to prompt garbage collection (GC). This should be
+far less necessary with ART, particularly if you're invoking garbage collection
+to prevent <a
+href="{@docRoot}/tools/debugging/debugging-memory.html#LogMessages"><code>GC_FOR_ALLOC</code></a>-type
+occurrences or to reduce fragmentation. You can verify which runtime is in use
+by calling {@link java.lang.System#getProperty(java.lang.String)
+System.getProperty("dalvik.vm.version")}. If ART is in use, the property's value
+is <code>"2.0.0"</code> or higher.</p>
+
+<p>Furthermore, a compacting garbage collector is under development in the <a
+href="https://source.android.com">Android Open-Source Project (AOSP)</a> to
+improve memory management. Because of this, you should avoid using techniques
+that are incompatible with compacting GC (such as saving pointers to object
+instance data). This is particularly important for apps that make use of the
+Java Native Interface (JNI). For more information, see <a
+href="#JNI_Issues">Preventing JNI Issues</a>.</p>
+
+<h2 id="JNI_Issues">Preventing JNI Issues</h2>
+
+<p>ART's JNI is somewhat stricter than Dalvik's. It is an especially good idea
+to use CheckJNI mode to catch common problems. If your app makes use of C/C++
+code, you should review the following article:</p>
+
+<p><a
+href="http://android-developers.blogspot.com/2011/07/debugging-android-jni-with-checkjni.html">Debugging
+Android JNI with CheckJNI</a></p>
+
+<h3 id="JNI_and_GC">Checking JNI code for garbage-collection issues</h3>
+
+<p>ART has a compacting garbage collector under development on the
+Android Open Source Project (AOSP). Once the compacting garbage collector is in
+use, objects may be moved in memory. If you use C/C++ code, do not
+perform operations that are incompatible with compacting GC. We have enhanced
+CheckJNI to identify some potential issues (as described in <a
+href="http://android-developers.blogspot.com/2011/11/jni-local-reference-changes-in-ics.html">JNI
+Local Reference Changes in ICS</a>).</p>
+
+<p>One area to watch for in particular is the use of
+<code>Get...ArrayElements()</code> and <code>Release...ArrayElements()</code>
+functions. In runtimes with non-compacting GC, the
+<code>Get...ArrayElements()</code> functions typically return a reference to the
+actual memory backing the array object. If you make a change to one of the
+returned array elements, the array object is itself changed (and the arguments
+to <code>Release...ArrayElements()</code> are usually ignored). However, if
+compacting GC is in use, the <code>Get...ArrayElements()</code> functions may
+return a copy of the memory. If you misuse the reference when compacting GC is
+in use, this can lead to memory corruption or other problems. For example:</p>
+
+<ul>
+
+ <li>If you make any changes to the returned array elements, you must call the
+ appropriate <code>Release...ArrayElements()</code> function when you are done,
+ to make sure the changes you made are correctly copied back to the underlying
+ array object.</li>
+
+ <li>When you release the memory array elements, you must use the appropriate
+ mode, depending on what changes you made:
+
+ <ul>
+
+ <li>If you did not make any changes to the array elements, use
+ <code>JNI_ABORT</code> mode, which releases the memory without copying
+ changes back to the underlying array object.</li>
+
+ <li>If you made changes to the array, and do not need the reference any
+ more, use code <code>0</code> (which updates the array object and frees
+ the copy of the memory).</li>
+
+ <li>If you made changes to the array that you want to commit, and you want
+ to keep the copy of the array, use <code>JNI_COMMIT</code> (which updates
+ the underlying array object and retains the copy).</li>
+
+ </ul>
+
+ </li>
+
+ <li>When you call <code>Release...ArrayElements()</code>, return the same
+ pointer that was originally returned by <code>Get...ArrayElements()</code>. For
+ example, it's not safe to increment the original pointer (to scan through the
+ returned array elements) then pass the incremented pointer to
+ <code>Release...ArrayElements()</code>. Passing this modified pointer can cause
+ the wrong memory to be freed, resulting in memory corruption.</li>
+
+</ul>
+
+<h3 id="Error_Handling">Error handling</h3>
+
+<p>ART's JNI throws errors in a number of cases where Dalvik didn’t. (Once
+again, you can catch many such cases by testing with CheckJNI.)</p>
+
+<p>For example, if <code>RegisterNatives</code> is called with a method that
+does not exist (perhaps because the method was removed by a tool such as
+<strong>ProGuard</strong>), ART now properly throws {@link
+java.lang.NoSuchMethodError}:</p>
+
+<pre class="no-pretty-print">
+08-12 17:09:41.082 13823 13823 E AndroidRuntime: FATAL EXCEPTION: main
+08-12 17:09:41.082 13823 13823 E AndroidRuntime: java.lang.NoSuchMethodError:
+ no static or non-static method
+ "Lcom/foo/Bar;.native_frob(Ljava/lang/String;)I"
+08-12 17:09:41.082 13823 13823 E AndroidRuntime:
+ at java.lang.Runtime.nativeLoad(Native Method)
+08-12 17:09:41.082 13823 13823 E AndroidRuntime:
+ at java.lang.Runtime.doLoad(Runtime.java:421)
+08-12 17:09:41.082 13823 13823 E AndroidRuntime:
+ at java.lang.Runtime.loadLibrary(Runtime.java:362)
+08-12 17:09:41.082 13823 13823 E AndroidRuntime:
+ at java.lang.System.loadLibrary(System.java:526)
+</pre>
+
+<p>ART also logs an error (visible in logcat) if <code>RegisterNatives</code> is
+called with no methods:</p>
+
+<pre class="no-pretty-print">
+W/art ( 1234): JNI RegisterNativeMethods: attempt to register 0 native
+methods for <classname>
+</pre>
+
+<p>In addition, the JNI functions <code>GetFieldID()</code> and
+<code>GetStaticFieldID()</code> now properly throw {@link java.lang.NoSuchFieldError}
+instead of simply returning null. Similarly, <code>GetMethodID()</code> and
+<code>GetStaticMethodID()</code> now properly throw {@link java.lang.NoSuchMethodError}.
+This can lead to CheckJNI failures because of the unhandled exceptions or the
+exceptions being thrown to Java callers of native code. This makes it
+particularly important to test ART-compatible apps with CheckJNI mode.</p>
+
+<p>ART expects users of the JNI <code>CallNonvirtual...Method()</code> methods
+(such as <code>CallNonvirtualVoidMethod()</code>) to use the method's declaring
+class, not a subclass, as required by the JNI specification.</p>
+
+<h2 id="Stack_Size">Preventing Stack Size Issues</h2>
+
+<p>Dalvik had separate stacks for native and Java code, with a default Java
+stack size of 32KB and a default native stack size of 1MB. ART has a unified
+stack for better locality. Ordinarily, the ART {@link java.lang.Thread} stack
+size should be approximately the same as for Dalvik. However, if you explicitly
+set stack sizes, you may need to revisit those values for apps running in
+ART.</p>
+
+<ul>
+
+ <li>In Java, review calls to the {@link
+ java.lang.Thread#Thread(java.lang.ThreadGroup, java.lang.Runnable,
+ java.lang.String, long) Thread} constructor that specify an explicit stack
+ size. For example, you will need to increase the size if {@link
+ java.lang.StackOverflowError} occurs.</li>
+
+ <li>In C/C++, review use of <code>pthread_attr_setstack()</code> and
+ <code>pthread_attr_setstacksize()</code> for threads that also run Java code via
+ JNI. Here is an example of the error logged when an app attempts to call JNI
+ <code>AttachCurrentThread()</code> when the pthread size is too small:
+
+<pre class="no-pretty-print">F/art: art/runtime/thread.cc:435]
+ Attempt to attach a thread with a too-small stack (16384 bytes)</pre>
+ </li>
+
+</ul>
+
+<h2 id="Object_Model_Changes">Object model changes</h2>
+
+<p>Dalvik incorrectly allowed subclasses to override package-private methods.
+ART issues a warning in such cases:</p>
+
+<pre class="no-pretty-print">
+Before Android 4.1, method void com.foo.Bar.quux()
+would have incorrectly overridden the package-private method in
+com.quux.Quux
+</pre>
+
+<p>If you intend to override a class's method in a different package, declare the
+method as <code>public</code> or <code>protected</code>.</p>
+
+<p>{@link java.lang.Object} now has private fields. Apps that reflect on fields
+in their class hierarchies should be careful not to attempt to look at the
+fields of {@link java.lang.Object}. For example, if you are iterating up a class
+hierarchy as part of a serialization framework, stop when
+
+<pre>Class.getSuperclass() == java.lang.Object.class</pre>
+
+instead of continuing until the method returns <code>null</code>.</p>
+
+<p>Proxy {@link
+java.lang.reflect.InvocationHandler#invoke(java.lang.Object,java.lang.reflect.Method,java.lang.Object[])
+InvocationHandler.invoke()} now receives <code>null</code> if there are no
+arguments instead of an empty array. This behavior was documented previously but
+not correctly handled in Dalvik. Previous versions of <a
+href="https://code.google.com/p/mockito/">Mockito</a> have difficulties with
+this, so use an updated Mockito version when testing with ART.</p>
+
+<h2 id="AOT_Fails">Fixing AOT Compilation Issues</h2>
+
+<p>ART's Ahead-Of-Time (AOT) Java compilation should work for all standard Java
+code. Compilation is performed by ART's
+<code>dex2oat</code> tool; if you encounter any issues related to
+<code>dex2oat</code> at install time, let us know (see <a
+href="#Reporting_Problems">Reporting Problems</a>) so we can fix them as quickly
+as possible. A couple of issues to note:</p>
+
+<ul>
+
+ <li>ART does tighter bytecode verification at install time than Dalvik does.
+ Code produced by the Android build tools should be fine. However, some
+ post-processing tools (especially tools that perform obfuscation) may produce
+ invalid files that are tolerated by Dalvik but rejected by ART. We have been
+ working with tool vendors to find and fix such issues. In many cases, getting
+ the latest versions of your tools and regenerating the DEX files can fix these
+ problems.</li>
+
+ <li>Some typical problems that are flagged by the ART verifier include:
+ <ul>
+ <li>invalid control flow</li>
+ <li>unbalanced <code>moniterenter</code>/<code>moniterexit</code></li>
+ <li>0-length parameter type list size</li>
+ </ul>
+ </li>
+
+ <li>Some apps have dependencies on the installed <code>.odex</code> file
+ format in <code>/system/framework</code>, <code>/data/dalvik-cache</code>, or
+ in {@link dalvik.system.DexClassLoader}’s optimized output directory. These
+ files are now ELF files and not an extended form of DEX files. While ART tries
+ to follow the same naming and locking rules as Dalvik, apps should not depend
+ on the file format; the format is subject to change without notice.</li>
+
+
+
+<h2 id="Reporting_Problems">Reporting Problems</h2>
+
+<p>If you run into any issues that aren’t due to app JNI issues, report
+them via the Android Open Source Project Issue Tracker at <a
+href="https://code.google.com/p/android/issues/list">https://code.google.com/p/android/issues/list</a>.
+Include an <code>"adb bugreport"</code> and a link to the app in the Google
+Play store if available. Otherwise, if possible, attach an APK that reproduces
+the issue. Note that issues (including attachments) are publicly
+visible.</p>
diff --git a/docs/html/images/gp-ads-console.jpg b/docs/html/images/gp-ads-console.jpg
new file mode 100644
index 0000000..158e31d
--- /dev/null
+++ b/docs/html/images/gp-ads-console.jpg
Binary files differ
diff --git a/docs/html/images/gp-ads-linking2.jpg b/docs/html/images/gp-ads-linking2.jpg
new file mode 100644
index 0000000..0c2f731
--- /dev/null
+++ b/docs/html/images/gp-ads-linking2.jpg
Binary files differ
diff --git a/docs/html/images/gp-analytics.jpg b/docs/html/images/gp-analytics.jpg
new file mode 100644
index 0000000..e1a92c7
--- /dev/null
+++ b/docs/html/images/gp-analytics.jpg
Binary files differ
diff --git a/docs/html/images/tools-home.png b/docs/html/images/tools-home.png
index 291a361..86a7414 100644
--- a/docs/html/images/tools-home.png
+++ b/docs/html/images/tools-home.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index a4b0683..de2980b 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -1,159 +1,95 @@
fullpage=true
page.viewport_width=970
-no_footer_links=true
-carousel=true
excludeFromSuggestions=true
page.metaDescription=The official site for Android developers. Provides the Android SDK and documentation for app developers and designers.
page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3f61-WpRguHq-aNjtF7xJjMTSi79as" />
@jd:body
+<!-- Top full-bleed carousel -->
+<div class="home-new-carousel-1">
+ <div class="fullscreen-carousel-content">
+ <div class="vcenter">
+ <div class="wrap clearfix">
+ <div class="resource-widget resource-flow-layout wrap col-16"
+ data-query="collection:index/primary"
+ data-resourceStyle="card"
+ data-sortOrder="-timestamp"
+ data-numStacks="3"
+ data-maxResults="4"
+ data-cardSizes="18x6,6x2,6x2,6x2">
+ </div> <!-- end .resource-widget -->
+ </div> <!-- end .wrap -->
+ </div> <!-- end .vcenter -->
+ </div> <!-- end .fullscreen-carousel-content -->
+</div> <!-- end .fullscreen-carousel -->
-<div class="wrap">
- <!-- Slideshow -->
- <div class="slideshow-container slideshow-home col-16">
- <a href="" class="slideshow-prev">Prev</a>
- <a href="" class="slideshow-next">Next</a>
- <div class="frame">
- <ul>
- <!-- set explicit widths as needed to prevent overflow issues -->
+<div class="actions-bar">
+ <div class="wrap">
+ <div class="actions">
+ <div><a href="{@docRoot}sdk/index.html">Get the SDK</a></div>
+ <div><a href="{@docRoot}samples/index.html">Browse Samples</a></div>
+ <div><a href="//www.youtube.com/user/androiddevelopers">Watch Videos</a></div>
+ <div><a href="{@docRoot}distribute/googleplay/developer-console.html">Manage Your Apps</a></div>
+ </div><!-- end .actions -->
+ </div><!-- end .wrap -->
+</div><!-- end .actions-bar -->
- <li class="item carousel-home">
- <div class="content-left col-10" style="width:580px;">
- <a href="{@docRoot}wear/index.html">
- <img src="{@docRoot}images/home/aw_dac.png" style="margin-top:50px" >
- </a>
- </div>
- <div class="content-right col-5" style="width:280px;">
- <h1>Introducing Android Wear</h1>
- <p>We’re extending the Android platform to wearables. You can start building richer wearable experiences for your apps today using the enhanced Notification APIs in this Developer Preview.</p>
- <p>We can’t wait to see what you will create.</p>
- <p><a href="{@docRoot}wear/index.html" class="button">Learn more</a></p>
- </div>
- </li>
-
- <li class="item carousel-home">
- <div class="content-left col-11" style="padding-top:65px;">
- <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
- <div style="box-shadow: 3px 10px 18px 1px #999;width:600px;height:336px">
- <div id="ytapiplayer">
- <a href="http://www.youtube.com/watch?v=WWArLD6nqrk"><img width=600 src="{@docRoot}images/video-kiwi.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
- </div>
- <script type="text/javascript">
- var params = { allowScriptAccess: "always" };
- var atts = { id: "ytapiplayer" };
- swfobject.embedSWF("//www.youtube.com/v/WWArLD6nqrk?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
- "ytapiplayer", "600", "336", "8", null, null, params, atts);
-
- // Callback used to pause/resume carousel based on video state
- function onytplayerStateChange(newState) {
- var isPaused = $("#pauseButton").hasClass("paused");
- if ((newState == 1) || (newState == 3)) {
- // if playing or buffering, pause the carousel
- if (!isPaused) {
- $("#pauseButton").click();
- }
- } else {
- // otherwise, make sure carousel is running
- if (isPaused) {
- $("#pauseButton").click();
- }
- }
- }
-
- // Callback received when YouTube player loads to setup callback (above)
- function onYouTubePlayerReady(playerId) {
- var ytplayer = document.getElementById("ytapiplayer");
- ytplayer.addEventListener("onStateChange", "onytplayerStateChange");
- }
-
- </script>
- </div>
- </div>
- <div class="content-right col-4">
- <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Kiwi, Inc.</h1>
- <p>Game developer Kiwi has had five titles in the top 25 grossing on Google Play. Hear how Google Play
- has helped them double revenue every six months.</p>
- <p><a href="{@docRoot}distribute/stories/index.html" class="button">Watch more videos </a></p>
- </div>
- </li>
-
- <li class="item carousel-home">
- <div class="content-left col-7" style="width:400px;">
- <a href="{@docRoot}about/versions/kitkat.html">
- <img src="{@docRoot}images/home/kk-hero.jpg" width="242" style="padding-top:72px;">
- </a>
- </div>
- <div class="content-right col-4" style="width:340px;">
- <h1>Android 4.4 KitKat!</h1>
- <p>A new version of Android is here, with great new features, APIs, and tools for developers.</p>
- <p>Android 4.4 is built to run on more devices than ever before, and gives you more ways to showcase your content and create beautiful, useful, and innovative apps.</p>
- <p>Learn about what's new in the Platform Highlights and see the API Overview for details.</p>
- <p><a href="{@docRoot}about/versions/kitkat.html" class="button">Check out the highlights</a></p>
- </div>
- </li>
-
- <li class="item carousel-home">
- <div class="content-left col-11" style="padding-top:65px;">
- <a href="https://www.youtube.com/watch?v=sONcojECWXs&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K&index=1">
- <img src="{@docRoot}images/title-devbytes-kk.jpg" style="margin-top:0px;width:600px;">
- </a>
- </div>
- <div class="content-right col-4">
- <h1 style="white-space:nowrap;line-height:1.2em;">DevBytes: <br />Android 4.4</h1>
- <p>Join the DevBytes team for a look at what's new in Android 4.4 KitKat — new ways to make your apps beautiful, printing, storage access framework, and more.</p>
- <p><a href="https://www.youtube.com/watch?v=sONcojECWXs&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K&index=1" class="button">Watch the video </a></p>
- </div>
- </li>
-
- <li class="item carousel-home">
- <div class="content-left col-19" style="width:580px;">
- <a href="{@docRoot}design/patterns/new.html">
- <img src="{@docRoot}design/media/design_elements_landing.png" style="margin-top:30px">
- </a>
- </div>
- <div class="content-right col-4" style="width:280px;">
- <h1>Design for Android KitKat</h1>
- <p>Android KitKat brings a refreshed UI with updated styles, patterns, and gestures to use in your apps. </p>
- <p>We've updated the Android Design guidelines and added new pages on branding, fullscreen, and more. </p>
- <p><a href="{@docRoot}design/patterns/new.html" class="button">See what's new</a></p>
- </div>
- </li>
-
- <li class="item carousel-home">
- <div class="content-left col-11" style="padding-top:65px;">
- <a href="http://www.youtube.com/watch?v=6QHkv-bSlds&list=PLWz5rJ2EKKc8j2B95zGMb8muZvrIy-wcF&index=1">
- <img src="{@docRoot}images/title-adia-kk.png" style="margin-top:0px;width:600px;">
- </a>
- </div>
- <div class="content-right col-4">
- <h1 style="white-space:nowrap;line-height:1.2em;">ADIA: <br />Android 4.4</h1>
- </p>Join the Android Design in Action team for a walkthrough of new developer features, UX changes, and updates to design guidelines in Android 4.4.</p>
- <p><a href="http://www.youtube.com/watch?v=6QHkv-bSlds&list=PLWz5rJ2EKKc8j2B95zGMb8muZvrIy-wcF&index=1" class="button">Watch the video </a></p>
- </div>
- </li>
- </ul>
+<div class="landing-rest-of-page">
+ <div class="landing-section" style="background-color:#f5f5f5">
+ <div class="wrap">
+ <div class="landing-section-header">
+ <div class="landing-h1">Android, Everywhere You Need It</div>
+ <div class="landing-subhead">
+ Android runs on hundreds of millions of handheld devices around the world, <br /> and it now supports these exciting, new form-factors.
</div>
- </div>
+ </div>
+ <div class="landing-body">
+ <div class="landing-breakout cols">
-<!-- /End slideshow -->
+ <!-- <div class="resource-widget resource-flow-layout col-16" data-query="collection:index/devices"
+ data-sortorder="" data-cardsizes="6x6, 6x6, 6x6" data-maxresults="3"></div>-->
- <a href="" id="pauseButton" style="display:none">pause</a>
+ <div class="col-3-wide">
+ <img src="" alt="">
+ <p>Wear</p>
+ <p class="landing-small">
+ Provide information on-the-go for your users, whenever they need it.
+ </p>
+ <p class="landing-small">
+ <a href="{@docRoot}wear">Learn about Android Wear</a>
+ </p>
+ </div>
-</div>
-<div class="wrap" style="padding-bottom:20px">
- <!-- Section links -->
- <div class="home-sections">
- <ul>
- <li><a href="{@docRoot}about/index.html">About Android</a></li>
- <li><a href="{@docRoot}sdk/index.html">Get the SDK</a></li>
- <li><a href="http://source.android.com">Open Source</a></li>
- <li><a href="{@docRoot}support.html">Support</a></li>
- <li class="last"><a href="{@docRoot}legal.html">Legal</a></li>
- </ul>
- </div>
- <!-- /Section links -->
-</div>
+ <div class="col-3-wide">
+ <img src="" alt="">
+
+ <p>TV</p>
+ <p class="landing-small">
+ Build your apps for the big screen and bring your content to life.
+ </p>
+ <p class="landing-small">
+ <a href="{@docRoot}tv">Learn about Android TV</a>
+ </p>
+ </div>
+
+ <div class="col-3-wide">
+ <img src="" alt="">
+
+ <p>Auto</p>
+ <p class="landing-small">
+ Extend your music apps to automobile
+ entertainment systems.
+ </p>
+ <p class="landing-small">
+ <a href="{@docRoot}auto">Learn about Android Auto</a>
+ </p>
+ </div>
+
+ </div>
+ </div>
+ </div> <!-- end .wrap -->
+ </div> <!-- end .landing-section -->
\ No newline at end of file
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index 8a4ac47..ca19c02 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -1,4 +1,21 @@
var RESOURCE_COLLECTIONS = {
+ "index/primary": {
+ "title": "",
+ "resources": [
+ "preview/index.html",
+ "preview/material/index.html",
+ "preview/material/index.html",
+ "preview/material/index.html"
+ ]
+ },
+ "index/devices": {
+ "title": "",
+ "resources": [
+ "wear/index.html",
+ "tv/index.html",
+ "auto/index.html"
+ ]
+ },
"launch/static": {
"title": "",
"resources": [
@@ -49,7 +66,8 @@
"distribute/users/your-listing.html",
"distribute/users/build-buzz.html",
"distribute/users/build-community.html",
- "distribute/users/expand-to-new-markets.html"
+ "distribute/users/expand-to-new-markets.html",
+ "distribute/users/promote-with-ads.html"
]
},
"distribute/engagelanding": {
@@ -60,6 +78,7 @@
"distribute/engage/easy-signin.html",
"distribute/engage/deep-linking.html",
"distribute/engage/game-services.html",
+ "distribute/engage/analytics.html",
"distribute/engage/app-updates.html",
"distribute/engage/community.html",
"distribute/engage/video.html"
@@ -214,6 +233,13 @@
"distribute/stories/localization.html"
]
},
+ "distribute/users/promotewithads": {
+ "title": "",
+ "resources": [
+ "http://www.google.com/ads/admob/#subid=us-en-et-dac",
+ "distribute/essentials/optimizing-your-app.html"
+ ]
+ },
"distribute/users/buildbuzz": {
"title": "",
"resources": [
@@ -394,6 +420,14 @@
"http://play.google.com/about/developer-content-policy.html"
]
},
+ "distribute/engage/analytics": {
+ "title": "",
+ "resources": [
+ "http://www.google.com/analytics/mobile/",
+ "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html",
+ "https://developers.google.com/analytics/devguides/collection/android/"
+ ]
+ },
"distribute/engage/widgets": {
"title": "",
"resources": [
diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js
index f26b747b..d8db5bf 100644
--- a/docs/html/jd_extras.js
+++ b/docs/html/jd_extras.js
@@ -726,6 +726,21 @@
"tags": [
"#engagement",
],
+ "url": "http://www.google.com/analytics/mobile/",
+ "timestamp": 1383243492000,
+ "image": "http://www.google.com//analytics/images/heros/mobile-index.jpg",
+ "title": "Google Mobile App Analytics",
+ "summary": "Mobile App Analytics measures what matters most at all key stages: from first discovery and download to in-app purchases. ",
+ "keywords": ["analytics,user behavior"],
+ "type": "guide",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [
+ "#engagement",
+ ],
"url": "https://developers.google.com/app-indexing/",
"timestamp": 1383243492000,
"image": "https://developers.google.com/app-indexing/images/allthecooks_srp.png",
@@ -1101,4 +1116,17 @@
"type": "Google+",
"titleFriendly": ""
},
+ {
+ "lang": "en",
+ "group": "",
+ "tags": ["analytics"],
+ "url": "https://developers.google.com/analytics/devguides/collection/android/",
+ "timestamp": null,
+ "image": "https://developers.google.com/analytics/images/home/gear-logo.png",
+ "title": "Google Mobile App Analytics SDK",
+ "summary": "The Google Analytics for Mobile Apps SDKs make it easy for you to implement Google Analytics in your mobile application.",
+ "keywords": ["analytics, user behavior"],
+ "type": "sdk",
+ "titleFriendly": ""
+ }
]);
\ No newline at end of file
diff --git a/docs/html/jd_tag_helpers.js b/docs/html/jd_tag_helpers.js
index ca01386..b0fe67a 100644
--- a/docs/html/jd_tag_helpers.js
+++ b/docs/html/jd_tag_helpers.js
@@ -7,6 +7,7 @@
}
var ALL_RESOURCES = mergeArrays(
+ ABOUT_RESOURCES,
DESIGN_RESOURCES,
DISTRIBUTE_RESOURCES,
GOOGLE_RESOURCES,
diff --git a/docs/html/preview/api-overview.jd b/docs/html/preview/api-overview.jd
new file mode 100644
index 0000000..40618a3
--- /dev/null
+++ b/docs/html/preview/api-overview.jd
@@ -0,0 +1,698 @@
+page.title=L Developer Preview APIs
+excludeFromSuggestions=true
+sdk.platform.apiLevel=20
+@jd:body
+
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document
+ <a href="#" onclick="hideNestedItems('#toc44',this);return false;" class="header-toggle">
+ <span class="more">show more</span>
+ <span class="less" style="display:none">show less</span></a></h2>
+
+<ol id="toc44" class="hide-nested">
+ <li><a href="#Behaviors">Important Behavior Changes</a>
+ <ol>
+ <li><a href="#BehaviorNotifications">If your app implements notifications...</a></li>
+ <li><a href="#BehaviorFullscreen">If your app uses fullScreenIntent...</a></li>
+ <li><a href="#BehaviorGetRecentTasks">If your app uses ActivityManager.getRecentTasks()...</a></li>
+ </ol>
+ </li>
+ <li><a href="#UI">User Interface</a>
+ <ol>
+ <li><a href="#MaterialDesign">Material design support</a></li>
+ <li><a href="#LockscreenNotifications">Lockscreen notifications</a></li>
+ <li><a href="#NotificationsMetadata">Notifications metadata</a></li>
+ <li><a href="#Recents">Concurrent documents and activities in Recents screen</a></li>
+ <li><a href="#WebView">WebView updates</a></li>
+ </ol>
+ </li>
+ <li><a href="#UserInput">User Input</a>
+ <ol>
+ <li><a href="#IME">IME bug fixes and improvements</a></li>
+ </ol>
+ </li>
+ <li><a href="#Animations">Animation & Graphics</a>
+ <ol>
+ <li><a href="#OpenGLES-3-1">Support for OpenGL ES 3.1</a></li>
+ </ol>
+ </li>
+ <li><a href="#Multimedia">Multimedia</a>
+ <ol>
+ <li><a href="#Camera-v2">Camera V2</a></li>
+ <li><a href="#AudioPlayback">Audio playback</a></li>
+ <li><a href="#MediaPlaybackControl">Media playback control</a></li>
+ </ol>
+ </li>
+ <li><a href="#Storage">Storage</a>
+ <ol>
+ <li><a href="#DirectorySelection">Directory selection</a></li>
+ </ol>
+ </li>
+ <li><a href="#Wireless">Wireless and Connectivity</a>
+ <ol>
+ <li><a href="#Multinetwork">Dynamic network selection and seamless handoff</a></li>
+ <li><a href="#BluetoothBroadcasting">Bluetooth broadcasting</a></li>
+ <li><a href="#NFCEnhancements">NFC enhancements for payments</a></li>
+ </ol>
+ </li>
+ <li><a href="#Power">Power Efficiency</a>
+ <ol>
+ <li><a href="#JobScheduler">Scheduling Jobs</a></li>
+ <li><a href="#PowerMeasurementTools">Developer tools and APIs for power measurement</a>
+ </ol>
+ </li>
+ <li><a href="#Enterprise">Enterprise</a>
+ <ol>
+ <li><a href="#ManagedProvisioning">Managed provisioning</a></li>
+ </ol>
+ </li>
+ <li><a href="#Printing">Printing Framework</a>
+ <ol>
+ <li><a href="#PDFRender">PDF rendering</a></li>
+ </ol>
+ </li>
+ <li><a href="#TestingA11y">Testing & Accessibility</a>
+ <ol>
+ <li><a href="#TestingA11yImprovements">Testing and accessibility improvements</a></li>
+ </ol>
+ </li>
+ <li><a href="#Manifest">Manifest Declarations</a>
+ <ol>
+ <li><a href="#ManifestFeatures">Declarable required features</a></li>
+ <li><a href="#ManifestPermissions">User permissions</a></li>
+ </ol>
+ </li>
+</ol>
+
+<h2>See also</h2>
+<ol>
+<li><a href="{@docRoot}sdk/api_diff/20/changes.html">API
+Differences Report »</a> </li>
+</ol>
+
+</div>
+</div>
+
+<p>L is an upcoming release for the Android platform
+that offers new features for users and app developers. This document provides
+an introduction to the most notable new APIs.</p>
+
+<p>L is currently available as a <strong>developer preview</strong> intended
+for early adopters and testers. If you are interested in influencing the
+direction of the Android framework,
+<a href="{@docRoot}preview/setup-sdk.html">give the L Developer Preview a
+try</a> and send us your feedback!</p>
+
+<p class="caution"><strong>Caution:</strong>You should not publish apps
+using L Developer Preview to the Google Play store.</p>
+
+<h2 id="Behaviors">Important Behavior Changes</h2>
+
+<p>If you have previously published an app for Android, be aware that your app
+ might be affected by changes in L.</p>
+
+<h3 id="BehaviorNotifications">If your app implements notifications...</h3>
+
+<p>Notifications will be drawn with dark text atop white (or very light)
+backgrounds to match the new material design widgets. Make sure that all your
+notifications look right with the new color scheme. You should remove or update
+assets and text styles that involve color. The system will automatically invert
+action icons in notifications. Use
+{@code android.app.Notification.Builder.setColor()} to set an accent color
+in a circle behind your {@code Notification.icon} image.</p>
+
+<p>The system will ignore all non-alpha channels in action icons and the main
+notification icon, so you should assume that these icons will be alpha-only.
+</p>
+
+<p>If you are currently adding sounds and vibrations to your notifications by
+using the {@link android.media.Ringtone}, {@link android.media.MediaPlayer},
+or {@link android.os.Vibrator} classes, make sure to remove this code so that
+the system can present notifications correctly in Do not disturb mode. You
+should use the {@link android.app.Notification.Builder} methods instead to add
+sounds and vibration.
+</p>
+
+<h3 id="BehaviorMediaControl">If your app uses RemoteControlClient...</h3>
+
+<p>Lockscreens in L will not show transport controls for your
+{@link android.media.RemoteControlClient}. Instead, your app can provide
+media playback control from the lockscreen through a media notification. This
+gives your app more control over the presentation of media buttons, while
+providing a consistent experience for users across the lockscreen and
+unlocked device.</p>
+
+<p>You must call {@code Notification.Builder.setVisibility(Notification.VISIBILITY_PUBLIC)} to mark your media notification as safe to reveal, even when the lockscreen is secured
+with a PIN, pattern, or password.</p>
+
+<h3 id="BehaviorFullscreen">If your app uses fullScreenIntent...</h3>
+
+<p>Notifications now appear in a small floating window if all these conditions
+are met: the user’s activity is in fullscreen mode, the screen is on, and the
+device is unlocked. If your app implements fullscreen activities, make sure that
+these heads-up notifications are presented correctly.</p>
+
+<h3 id="BehaviorGetRecentTasks">If your app uses ActivityManager.getRecentTasks()...</h3>
+
+<p>With the introduction of the new document tasks feature in L (see below),
+the {@code android.app.ActivityManager.getRecentTasks()} method is now
+deprecated to improve user privacy. For backwards
+compatibility, it will still return a small subset of its data including the
+calling application’s own tasks and possibly some other non-sensitive tasks
+such as home. If your app is using this method to retrieve its own tasks,
+use {@code android.app.ActivityManager.getAppTasks()} instead to retrieve that
+information.</p>
+
+<h2 id="UI">User Interface</h2>
+
+<h3 id="MaterialDesign">Material design support</h3>
+
+<p>The L Developer Preview adds support for the material design style. You can create
+material design apps that are visually dynamic and have UI element transitions
+which feel natural and delightful to users. This support includes:</p>
+<ul>
+ <li>The Material theme</li>
+ <li>View shadows</li>
+ <li>The {@code RecyclerView} widget</li>
+ <li>Drawable animation and styling effects</li>
+ <li>Material design animation and activity transition effects</li>
+ <li>Animators for view properties based on the state of a view</li>
+ <li>Customizable UI widgets and app bars with color palettes that you control</li>
+</ul>
+<p>To learn more about adding material design functionality to your app, see
+<a href="{@docRoot}preview/material/index.html">Material design on Android</a>.</p>
+
+<h3 id="LockscreenNotifications">Lockscreen notifications</h3>
+<p>Lockscreens in the L Developer Preview have the ability to present notifications.
+Users can choose via <em>Settings</em> whether to allow sensitive notification
+content to be shown over a secure lockscreen.</p>
+
+<p>Your app can control the level of detail visible when its notifications are
+displayed over the secure lockscreen. To control the visibility level, call
+{@code android.app.Notification.Builder.setVisibility()} and specify one of these
+values:</p>
+<ul>
+<li>{@code VISIBILITY_PRIVATE}. Shows basic information, such as the
+notification’s icon, but hides the notification’s full content. If you want to
+provide a redacted public version of your notification for the system to display
+on a secure lockscreen, set the public notification object in the <code>publicVersion</code>
+field.</li>
+<li>{@code VISIBILITY_PUBLIC}. Shows the notification’s full content. This is
+ the system default if visibility is left unspecified.</li>
+<li>{@code VISIBILITY_SECRET}. Shows only the most minimal information,
+excluding even the notification’s icon.</li>
+</ul>
+
+<h3 id="NotificationsMetadata">Notifications metadata</h3>
+<p>The L Developer Preview uses metadata associated with your app notifications
+to more intelligently sort your notifications. The metadata you set also
+controls how the system presents your app notifications when the user is in <em>Do
+not disturb</em> mode. When constructing your notification, you can call the
+following methods in {@code android.app.Notification.Builder}:</p>
+
+<ul>
+<li>{@code setCategory()}. Allows the system to handle your app notifications
+in <em>Do not disturb mode</em> (for example, if your notification represents an
+incoming call, instant message, or alarm).</li>
+<li>{@code setPriority()}. Notifications with the priority field set to
+{@code PRIORITY_MAX} or {@code PRIORITY_HIGH} will appear in a small floating
+window if the notification also has sound or vibration.</li>
+<li>{@code addPerson()}. Allows you to add a list of people to a notification.
+Your app can use this to signal to the system that it should group together
+notifications from the specified people, or rank notifications from these
+people as being more important.</li>
+</ul>
+
+<h3 id="Recents">Concurrent documents and activities in the Recents screen</h3>
+
+<p>In previous releases, the
+<a href="{@docRoot}design/get-started/ui-overview.html">Recents screen</a>
+could only display a single task for each app that the user interacted with
+most recently. The L Developer Preview allows your app to open additional tasks
+for concurrent activities or documents. This feature facilitates multitasking
+by letting users quickly switch between individual activities and documents
+from the Recents screen. Examples of such concurrent tasks might include web
+pages in a browser app, documents in a productivity app, concurrent matches in
+a game, or chats in a messaging app. Your app can manage its tasks
+through the {@code android.app.ActivityManager.AppTask} class.</p>
+
+<p>To insert a logical break so that the system treats your activity as a new
+document, use {@code android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT} when
+launching the activity with {@link android.app.Activity#startActivity(android.content.Intent) startActivity()}. You can also get this behavior by declaring the
+<a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a>
+attribute {@code documentLaunchMode="intoExisting"} or {@code ="always"} in your
+manifest.</p>
+
+<p>You can also mark that a task should be removed from the Recents screen
+when all its activities are closed by using {@code android.content.Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS} when starting the root activity for
+the task. You can also set this behavior for an activity by declaring the
+<a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a>
+attribute {@code autoRemoveFromRecents=“true”} in your manifest.</p>
+
+<p>To avoid cluttering the Recents screen, you can set the maximum number of
+tasks from your app that can appear in the Recents screen through the
+<a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a> attribute {@code android:maxRecent}. The current maximum that can be specified
+is 100 tasks per user.</a></p>
+
+<h3 id="WebView">WebView updates</h3>
+<p>The L Developer Preview updates the {@link android.webkit.WebView}
+implementation to Chromium M36, bringing security and stability enhancements,
+as well as bug fixes. The default user-agent string for a
+{@link android.webkit.WebView} running on the L Developer Preview has
+been updated to incorporate 36.0.0.0 as the version number.</p>
+
+<p>Additionally, this release brings support for the
+<a href="https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html">WebAudio</a>, <a href="https://www.khronos.org/webgl/">WebGL</a>, and
+<a href="http://www.webrtc.org/">WebRTC</a> open standards. To learn more about
+the new features included in this release, see <a href="https://developer.chrome.com/multidevice/webview/overview">WebView for Android</a>.</p>
+
+<h2 id="UserInput">User Input</h2>
+
+<h3 id="IME">IME bug fixes and improvements</h3>
+
+<p>Beginning in the L Developer Preview, users can more easily switch between
+all input method editors (IME) <a href="{@docRoot}guide/topics/text/creating-input-method.html">supported by the platform</a>. Performing the designated
+switching action (usually touching a Globe icon on the soft keyboard) will cycle
+among all such IMEs. This change takes place in
+{@code android.view.inputmethod.InputMethodManager.shouldOfferSwitchingToNextInputMethod()}.</p>
+
+<p>In addition, the framework will now check whether the next IME includes a
+switching mechanism at all, thus supporting switching to the IME after it. An
+IME with a switching mechanism will not cycle to an IME without one. This
+change takes place in
+{@code android.view.inputmethod.InputMethodManager.switchToNextInputMethod()}.
+
+<p>To see an example of how to use the updated IME-switching APIs, refer to the
+updated soft-keyboard implementation sample in this release.</p>
+
+<h2 id="Animations">Animation & Graphics</h2>
+
+<h3 id="OpenGLES-3-1">Support for OpenGL ES 3.1</h3>
+<p>The L Developer Preview adds Java interfaces and native support for OpenGL
+ES 3.1. Key new functionality provided in OpenGL ES 3.1 includes:</p>
+
+<ul>
+<li>Compute shaders
+<li>Separate shader objects
+<li>Indirect draw commands
+<li>Enhanced texturing functionality
+<li>Shading language improvements
+<li>Optional extensions for per-sample shading, advanced blending modes, and more
+<li>Backward compatibility with OpenGL ES 2.0 and 3.0
+</ul>
+
+<p>The Java interface for OpenGL ES 3.1 on Android is provided with GLES31. When using OpenGL ES 3.1, be sure that you declare it in your manifest file with the
+<a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}</a> tag and the {@code android:glEsVversion} attribute. For example:</p>
+
+<pre>
+<manifest>
+ <uses-feature android:glEsVersion="0x00030001" />
+ ...
+</manifest>
+</pre>
+
+<p>For more information about using OpenGL ES, including how to check the device’s supported OpenGL ES version at runtime, see the <a href="{@docRoot}/guide/topics/graphics/opengl.html">OpenGL ES API guide</a>.</p>
+
+<h2 id="Multimedia">Multimedia</h2>
+
+<h3 id="Camera=v2">Camera v2 API</h3>
+
+<p>The L Developer Preview introduces the new {@code android.hardware.camera2}
+API to facilitate fine grain photo capture and image processing. You can now programmatically access the camera devices available to the system with {@code CameraManager.getCameraIdList()} and connect to a specific device with {@code CameraManager.openCamera()}. To start capturing images, you
+need to create a {@code CameraCaptureSession} and specify the
+{@link android.view.Surface} objects to send the captured images. The {@code CameraCaptureSession} can be configured to take single shots or multiple images
+in a burst.</p>
+
+<p>To be notified when new images are captured, implement the
+{@code CameraCaptureSession.CaptureListener()} interface and set it in your
+capture request. Now when the system completes the image capture request, your
+{@code CameraCaptureSession.CaptureListener()} receives a call to
+{@code onCaptureCompleted()}, providing you with the image capture metadata in a
+{@code CaptureResult}.</p>
+
+<h3 id="AudioPlayback">Audio playback</h3>
+<p>This release includes the following changes for
+ {@code android.media.AudioTrack}:</p>
+<ul>
+ <li>Your app can now supply audio data in floating-point format
+({@code android.media.AudioFormat.ENCODING_PCM_FLOAT}). This permits greater
+dynamic range, more consistent precision, and greater headroom. Floating-point arithmetic is especially useful during intermediate calculations. Playback
+end-points use integer format for audio data, and with lower bit-depth. In L
+Developer Preview, portions of the internal pipeline are not yet floating-point.
+ <li>Your app can now supply audio data as a {@code ByteBuffer}, in the same
+format as provided by {@code MediaCodec}.
+ <li>The {@code WRITE_NON_BLOCKING} option can simplify buffering and
+ multithreading for some apps.
+</ul>
+
+<h3 id="MediaPlaybackControl">Media playback control</h3>
+<p>You can now build your own media controller app with the new
+{@code android.media.session.MediaController} class, which provides
+simplified transport controls APIs that replace those in
+{@code android.media.RemoteControlClient}. The {@code MediaController} class
+allows thread-safe control of playback from a non UI process, making it easier
+to control your media playback service from your app’s user interface.
+
+<p>You can also create multiple controllers to send playback commands,
+media keys, and other events to the same ongoing
+{@code android.media.session.MediaSession}. When you add a controller, you must
+call {@code MediaSession.getSessionToken()} to request an access
+token in order for your app to interact with the session.</p>
+
+<p>Send transport commands such as "play", "stop", "skip", and
+"set rating" by using {@code MediaController.TransportControls}. To handle
+in-bound media transport commands from controllers attached to the session, you
+should override the callback methods in
+{@code MediaSession.TransportControlsCallback}.</p>
+
+<p>You can also create rich notifications that allow playback control tied to a
+media session with the new {@code android.app.Notification.MediaStyle} class.</p>
+
+<h2 id="Storage">Storage</h2>
+
+<h3 id="DirectorySelection">Directory selection</h3>
+
+<p>The L Developer Preview extends the <a href="{@docRoot}guide/topics/providers/document-provider.html">Storage Access Framework</a> to let users
+select an entire directory, rather than individual files, to give your app
+read/write access to media files. When a directory is selected, your app also
+has access to all its child directories and content.</p>
+
+<p>To get the absolute paths to directories on external storage devices where
+applications can store media files, call the
+{@code android.content.Context.getExternalMediaDirs()} method. No additional
+permissions are needed by your app to read or write to the returned paths.
+External storage devices here are those considered by the system to be a
+permanent part of the device, and includes emulated external storage and
+physical media slots such as SD cards in battery compartments.</p>
+
+<p>If you want to access a document in an existing directory, call the
+{@code android.provider.DocumentsContract.buildDocumentViaUri()} method and pass
+in a Uri representing the path to the parent directory and the target document
+ID. The method returns a new {@link android.net.Uri} with which your app can
+use to write media content with {@code DocumentsContract.createDocument()}.
+
+<h2 id="Wireless">Wireless & Connectivity</h2>
+
+<h3 id="Multinetwork">Dynamic network selection and seamless handoff</h3>
+<p>The L Developer Preview provides new multi-networking APIs for your app to
+dynamically scan for available networks with specific capabilities, and
+establish a connection to them. This is useful when your app requires a
+specialized network, such as an SUPL, MMS, or carrier-billing network, or if
+you want to send data using a particular type of transport protocol.</p>
+
+<p>To select and connect to a network dynamically from your app, first
+instantiate a {@code android.net.ConnectivityManager}. Next, create a
+{@code android.net.NetworkRequest} to specify the network features and transport
+type your app is interested in. To start scanning for suitable networks, call
+{@code ConnectivityManager.requestNetwork()} or
+{@code ConnectivityManager.registerNetworkCallback(), and pass in the
+{@code NetworkRequest} object and an implementation of
+{@code ConnectivityManager.NetworkCallbackListener}.</p>
+
+<p>When the system detects a suitable network, it connects to the network and
+invokes the {@code NetworkCallbackListener.onAvailable()} callback. You can use
+the {@code android.net.Network} object from the callback to get additional
+information about the network, or to establish a socket connection.</p>
+
+<h3 id="BluetoothBroadcasting">Bluetooth broadcasting</h3>
+<p>Android 4.3 introduced platform support for <a href="{@docRoot}guide/topics/connectivity/bluetooth-le.html">Bluetooth Low Energy</a>
+(BLE) in the central role. In the L Developer Preview, an Android device can now
+act as a Bluetooth LE <em>peripheral device</em> and make its presence known to
+nearby devices. For instance, you can build apps that allow a device to
+function as a pedometer or health monitor and communicate its data with another
+BLE device.</p>
+
+<p>The new {@code android.bluetooth.le} APIs enable your apps to broadcast advertisements, scan for responses, and form connections with nearby BLE devices.
+You must add the {@code android.permission.BLUETOOTH_ADMIN} permission in your
+manifest in order for your app to use the new advertising and scanning features.</a>
+
+<p>To begin Bluetooth LE advertising so that other devices can discover the
+device running your app, call {@code android.bluetooth.le.BluetoothAdvertiser.startAdvisertising()} and pass in an implementation of the
+{@code android.bluetooth.le.AdvertiseCallback} class to report the success
+or failure of the advertising operation.</p>
+
+<p>Conversely, if you want to scan for Bluetooth LE devices nearby, call
+{@code android.bluetooth.le.BluetoothLeScanner.startScan()} and pass in an
+implementation of {@code android.bluetooth.le.ScanCallback} to report if a
+Bluetooth LE advertisement is found. Optionally, you can pass in filters to scan
+for a specific type of device.</p>
+
+<h3 id="NFCEnhancements">NFC enhancements</h3>
+<p>The L Developer Preview adds these enhancements to enable wider and more
+flexible use of NFC:</p>
+
+<ul>
+<li>Android Beam is now available in the share menu.
+<li>Support for the <a href="http://www.wi-fi.org/discover-wi-fi/wi-fi-direct">Wi-fi Direct standard</a>.
+<li>Your app can invoke the Android Beam on the user’s device to share data by
+calling {@code android.nfc.NfcAdapter.invokeBeam()}. This avoids the need for
+the user to manually tap the device against another NFC-capable device to
+complete the data transfer.
+<li>Use the new {@code android.nfc.NdefRecord.createTextRecord()} method if
+ you want to create an NDEF record containing UTF-8 text data.
+<li>If you are developing a payment app, you now have the ability to
+register an NFC application ID (AID) dynamically by calling
+{@code android.nfc.cardemulation.CardEmulation.registerAidsForService()}.
+You can also use {@code android.nfc.cardemulation.CardEmulation.setPreferredService()}
+to set the preferred card emulation service that should be used when a specific
+activity is in the foreground.
+</ul>
+
+<h2 id="Power">Power Efficiency</h2>
+
+<h3 id="JobScheduler">Scheduling jobs</h3>
+<p>The L Developer Preview provides a new {@code android.app.job.JobScheduler}
+API that lets you optimize battery life by defining jobs for the system to run
+asynchronously at a later time, such as when the device is charging. This is
+useful when you want to defer non user-facing units of work, have application
+code that accesses the network, or want to run a number of tasks as a batch on
+a regular schedule.</p>
+
+<p>A {@code android.app.job.JobInfo} object encapsulates such a unit of work,
+and provides an exact description of the criteria you are scheduling.</p>
+
+<p>Use the {@code android.app.job.JobInfo.Builder} to configure how the
+scheduled task should run. You can schedule the task to run under specific
+conditions such as only while the device is charging, when connected to an
+unmetered network, or when the system deems the device is idle.</p>
+
+<p>For example, you can add code like this to run your task on an
+unmetered network:</p>
+
+<pre>
+JobInfo uploadTask = new JobInfo.Builder(mJobId, mServiceComponent)
+ .setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED)
+ .build();
+
+JobScheduler jobScheduler =
+ (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE)
+jobScheduler.schedule(uploadTask);
+</pre>
+
+<h3 id="PowerMeasurementTools">Developer tools and APIs for power measurement</h3>
+<p>The L Developer Preview provides several new developer tools and APIs to help
+you better measure and understand your app's power usage.</p>
+
+<dl>
+<dt><strong>batterystats</strong></dt>
+<dd>
+<p>The {@code dumpsys batterystats} command allows you to generate interesting
+statistical data about battery usage on a device, organized by unique user ID
+(UID). The statistics generated by the tool include:</p>
+
+<ul>
+<li>History of battery related events
+<li>Global statistics for the device
+<li>Approximated power use per UID and system component
+<li>Per-app mobile ms per packet
+<li>System UID aggregated statistics
+<li>App UID aggregated statistics
+</ul>
+
+<p>Use the {@code --help} option to learn about the various options for
+tailoring the output. For example, to run the tool to print battery usage
+statistics since the device was last charged for a given app package, run this
+command:
+<pre>
+$ adb shell dumpsys batterystats --charged <package-name>
+</pre>
+</dd>
+
+<dt><strong>Battery Historian</strong></dt>
+<dd>
+<p>The Battery Historian tool ({@code historian.par}) analyzes L-based Android
+bug reports and creates an HTML visualization of power-related events. It can
+also visualize power consumption data from a power monitor, and will attempt to
+map power usage to the wakelocks seen. You can find the Battery Historian tool
+in {@code <sdk>/tools}.</p>
+
+<p>For best results, you should first enable full wakelock reporting to allow
+the Battery Historian tool to monitor uninterrupted over an extended period of
+time:</p>
+<pre>
+$ adb shell dumpsys batterystats --enable full-wake-history
+</pre>
+
+<p>You should also reset battery statistics at the beginning of a
+measurement:</p>
+<pre>
+$ adb shell dumpsys batterystats --reset
+</pre>
+
+<p>To generate an HTML visualization:</p>
+<pre>
+$ historian.par [-p powerfile] bugreport.txt > out.html
+</pre>
+</dd>
+
+<dt><strong>On-device power management</strong></dt>
+<dd>
+<p>You can use the {@code android.os.BatteryManager} API to obtain power
+consumption information based on the battery fuel gauge included in Android
+phones and tablets. This is useful in cases when it is not convenient to
+connect external measurement equipment to the Android device.</p>
+<p>To retrieve the battery properties, call {@code BatteryManager.getIntProperty()}
+or {@code BatteryManager.getLongProperty()}. The properties available, the
+exact resolution of the values of each, and other characteristics such as
+update frequency depend on the particular device being tested.</p>
+
+<p>The following properties can be inspected on all Android devices:</p>
+
+<table>
+ <tr>
+ <th>Property</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>{@code BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER}</td>
+ <td>Remaining battery capacity in microampere-hours.</td>
+ </tr>
+ <tr>
+ <td>{@code BatteryManager.BATTERY_PROPERTY_CURRENT_NOW}</td>
+ <td>Instantaneous battery current in microamperes.</td>
+ </tr>
+ <tr>
+ <td>{@code BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE}</td>
+ <td>Average battery current in microamperes</td>
+ </tr>
+ <tr>
+ <td>{@code BatteryManager.BATTERY_PROPERTY_CAPACITY}</td>
+ <td>Remaining battery capacity as an integer percentage.</td>
+ </tr>
+ <tr>
+ <td>{@code BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER}</td>
+ <td>Remaining energy in nanowatt-hours.</td>
+ </tr>
+</table>
+<dd>
+</dl>
+
+<h2 id="Enterprise">Enterprise</h2>
+<h3 id="ManagedProvisioning">Managed provisioning</h3>
+
+<p>The L Developer Preview provides new functionality for running apps within
+an enterprise environment:</p>
+<ul>
+<li><strong>Create managed user profiles</strong>. A device administrator can
+initiate a managed provisioning process to enroll a user device with an
+existing personal account into a co-present but separate managed profile that
+the administrator controls.
+<li><strong>Set device owner scope</strong>. Device administrators can also
+apply managed provisioning to configure a device that has no previous user
+accounts installed, so that they have full control over the device.
+</ul>
+
+<p>To start the manged provisioning process, send
+{@code ACTION_PROVISION_MANAGED_PROFILE} in an {@link android.content.Intent}. A
+user may be associated with more than one managed profile. To get a list of the
+managed profiles associated with the user, call
+{@code android.os.UserManager.getUserProfiles()}.</p>
+
+<p>Once a managed profile is created for a user, apps that are managed by the
+device administrator will appear alongside non-managed apps in the user’s
+Launcher, Recent apps screen, and notifications. A device policy management app
+can make the managed apps visually prominent by appending a “work” badge to the
+icon drawable with {@code android.os.UserManager.getBadgeDrawableForUser()}.</p>
+
+<p>If you are developing a Launcher app, you can use the new {@code android.content.pm.LauncherApps} class to get a list of launchable activities for the current user
+and any associated managed profiles.</p>
+
+<h2 id="Printing">Printing Framework</h2>
+
+<h3 id="PDFRender">Render PDF as bitmap</h3>
+<p>You can now render PDF document pages into bitmap images for printing by
+using the new {@code android.graphics.pdf.PdfRenderer} class. You must specify a
+{@code ParcelFileDescriptor} that is seekable (that is, the file can be randomly
+accessed) on which the system writes the the printable content. Your app can
+obtain a page for rendering with {@code openPage()}, then call {@code render()}
+to turn the opened {@code PdfRenderer.Page} into a bitmap. You can also set
+additional parameters if you only wan to convert a portion of the document into
+a bitmap image (for example, to implement <a href="http://en.wikipedia.org/wiki/Tiled_rendering">tile rendering</a> in order to zoom in on the document).</p>
+
+<h2 id="TestingA11y">Testing & Accessibility </h2>
+
+<h3 id="Testing A11yImprovements">Testing and accessibility improvements</h3>
+<p>The L Developer Preview adds the following support for testing and
+accessibility:</p>
+
+<ul>
+<li>You can use the new {@code android.app.UiAutomation.getWindowAnimationFrameStats()}
+and {@code android.app.UiAutomation.getWindowContentFrameStats()} methods to
+capture frame statistics for window animations and content. This lets you
+write instrumentation tests to evaluate if the app under test is rendering
+frames at a sufficient refresh frequency to provide a smooth user experience.
+<li>You can execute shell commands from your instrumentation test with the new
+{@code android.app.UiAutomation.executeShellCommand()}. The command execution
+is similar to running 'adb shell' from a host connected to the device. This
+allows you to use shell based tools such as {@code dumpsys}, {@code am},
+{@code content}, and {@code pm}.
+<li>Accessibility services and test tools that use the accessibility APIs
+(such as <a href="{@docRoot}tools/help/uiautomator/index.html">UiAutomator</a>)
+can now retrieve detailed information about the properties of windows on the
+screen that sighted users can interact with. To retrieve a list of
+{@code android.view.accessibility.AccessibilityWindowInfo} representing the
+windows information, call the new
+{@code android.accessibilityservice.AccessibilityService.getWindows()} method.
+<li>You can use the new {@code android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction} to define standard or customized
+actions to perform on an {@code android.view.accessibility.AccessibilityNodeInfo}.
+The new {@code AccessibilityAction} class replaces the actions-related APIs
+previously found in {@code AccessibilityNodeInfo}.
+</ul>
+
+<h2 id="manifest">Manifest Declarations</h2>
+
+<h3 id="ManifestFeatures">Declarable required features</h3>
+<p>The following values are now supported in the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}</a> element so you
+can ensure that your app is installed only on devices that provide the features
+your app needs.</p>
+
+<ul>
+<li>{@code FEATURE_LEANBACK}. Declares that your app must be installed only on devices that support the <a href="{@docRoot}tv}">Android TV</a> user interface. Example:
+<pre>
+<uses-feature android:name="android.software.leanback"
+ android:required="true" />
+</pre>
+
+<li>{@code FEATURE_MANAGEDPROFILES}. Declares that your app must only be installed on devices that support managed profiles for enterprise users. Example:
+<pre>
+<uses-feature android:name="android.software.managedprofiles"
+ android:required="true" />
+</pre>
+<li>{@code FEATURE_WEBVIEW}. Declares that your app must only be installed on devices that fully implement the android.webkit.* APIs. Example:
+<pre>
+<uses-feature android:name="android.software.webview"
+ android:required="true" />
+</pre>
+</ul>
+
+<h3 id="ManifestPermissions">User permissions</h3>
+<p>The following values are now supported in the <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code <uses-permission>}</a> to declare the
+permissions your app requires in order to access certain APIs.
+
+<ul>
+<li>{@code SIM_COMMUNICATION}. Required to communicate with a SIM card using
+ logical channels.
+</ul>
diff --git a/docs/html/preview/images/android.png b/docs/html/preview/images/android.png
new file mode 100644
index 0000000..3aeaa98
--- /dev/null
+++ b/docs/html/preview/images/android.png
Binary files differ
diff --git a/docs/html/preview/images/art.png b/docs/html/preview/images/art.png
new file mode 100644
index 0000000..c48f039
--- /dev/null
+++ b/docs/html/preview/images/art.png
Binary files differ
diff --git a/docs/html/preview/images/bugs.png b/docs/html/preview/images/bugs.png
new file mode 100644
index 0000000..46adf05
--- /dev/null
+++ b/docs/html/preview/images/bugs.png
Binary files differ
diff --git a/docs/html/preview/images/hero.jpg b/docs/html/preview/images/hero.jpg
new file mode 100644
index 0000000..1c52989
--- /dev/null
+++ b/docs/html/preview/images/hero.jpg
Binary files differ
diff --git a/docs/html/preview/images/material.png b/docs/html/preview/images/material.png
new file mode 100644
index 0000000..2d807d4
--- /dev/null
+++ b/docs/html/preview/images/material.png
Binary files differ
diff --git a/docs/html/preview/images/notifications.png b/docs/html/preview/images/notifications.png
new file mode 100644
index 0000000..2fb2fea
--- /dev/null
+++ b/docs/html/preview/images/notifications.png
Binary files differ
diff --git a/docs/html/preview/images/updates.png b/docs/html/preview/images/updates.png
new file mode 100644
index 0000000..f165c5a
--- /dev/null
+++ b/docs/html/preview/images/updates.png
Binary files differ
diff --git a/docs/html/preview/images/volta.png b/docs/html/preview/images/volta.png
new file mode 100644
index 0000000..9125081
--- /dev/null
+++ b/docs/html/preview/images/volta.png
Binary files differ
diff --git a/docs/html/preview/index.jd b/docs/html/preview/index.jd
new file mode 100644
index 0000000..e44e9f3
--- /dev/null
+++ b/docs/html/preview/index.jd
@@ -0,0 +1,236 @@
+page.title=Android L Developer Preview
+page.viewport_width=970
+fullpage=true
+no_footer_links=true
+page.type=about
+page.metaDescription=Test and build your apps against the next version of Android to ensure they're ready when the platform officially launches.
+page.image={@docRoot}preview/images/hero.jpg
+@jd:body
+
+<style>
+.fullpage>#footer,
+#jd-content>.content-footer.wrap {
+ display:none;
+}
+</style>
+
+<style>
+#footer {
+ display: none;
+}
+.content-footer {
+ display: none;
+}
+</style>
+
+<div class="landing-body-content">
+ <div class="landing-hero-container">
+ <div class="landing-section preview-hero">
+ <div class="landing-hero-scrim"></div>
+ <div class="landing-hero-wrap">
+ <div class="vertical-center-outer">
+ <div class="vertical-center-inner">
+
+ <div class="col-12">
+ <div class="landing-section-header">
+
+ <div class="landing-h1 hero">L Developer Preview</div>
+ <div class="landing-subhead hero">
+ <p>An early look at the next release</p>
+ </div>
+ <div class="landing-hero-description">
+ <p>Test and build your apps against the next<br />
+ version of Android to ensure they're ready<br/>
+ when the platform officially launches.</p>
+ </div>
+
+ <div class="landing-body">
+ <a href="/preview/setup-sdk.html" class="landing-button landing-primary" style="margin-top: 40px;">
+ Get Started
+ </a>
+ </div>
+ </div>
+
+ </div>
+ </div>
+ </div> <!-- end .wrap -->
+ <div class="landing-scroll-down-affordance">
+ <a class="landing-down-arrow" href="#extending-android-to-landingables">
+ <img src="/wear/images/carrot.png" alt="Scroll down to read more">
+ </a>
+ </div>
+ </div> <!-- end .landing-section .landing-hero -->
+ </div> <!-- end .landing-hero-container -->
+
+
+ <div class="landing-rest-of-page">
+ <div class="landing-section" id="extending-android-to-landingables">
+ <div class="wrap">
+ <div class="landing-section-header">
+ <div class="landing-h1">See What's New</div>
+ <div class="landing-subhead">
+ Take advantage of all the new capabilities, which are focused on design and performance.
+ </div>
+ </div>
+
+ <div class="landing-body">
+
+ <div class="landing-breakout cols">
+ <div class="col-4">
+ <img src="/preview/images/material.png" style="opacity:.6" alt="">
+ <p>A New UI Design</p>
+ <p class="landing-small">
+ Create a consistent experience across mobile and the web with
+ material design, the new Google-wide standard.
+ </p>
+ <p class="landing-small">
+ <a href="/preview/material/index.html">Learn about material</a>
+ </p>
+ </div>
+ <div class="col-4">
+ <img src="/preview/images/art.png" alt="">
+ <p>A Rehauled Runtime</p>
+ <p class="landing-small">
+ Test your apps and get them ready for <b>ART</b> (<b>A</b>ndroid <b>R</b>un<b>t</b>ime),
+ the default runtime in the next release.
+
+ </p>
+ <p class="landing-small">
+ <a href="/preview/api-overview.html#ART">Learn about ART</a>
+ </p>
+ </div>
+ <div class="col-4">
+ <img src="/preview/images/notifications.png" alt="">
+ <p style="width:230px">Enhanced Notifications</p>
+ <p class="landing-small">
+ Get more control over where notifications appear,
+ how they look, and automatic syncing to non-handheld devices.
+ </p>
+ <p class="landing-small">
+ <a href="/preview/api-overview.html#UI">Learn more</a>
+ </p>
+ </div>
+ <div class="col-4">
+ <img src="/preview/images/volta.png" alt="">
+ <p>Project Volta</p>
+ <p class="landing-small">
+ We've tuned the platform to be more energy efficient and
+ to give you more control over resource usage.
+ </p>
+ <p class="landing-small">
+ <a href="/preview/api-overview.html#Power">Learn more</a>
+ </p>
+ </div>
+ </div>
+ <p>See the <a href="{@docRoot}preview/api-overview.html">API overview</a> for more information
+ on the rest of the new and updated features.</p>
+ </div>
+ </div> <!-- end .wrap -->
+ </div> <!-- end .landing-section -->
+
+
+
+ <div class="landing-section landing-gray-background">
+ <div class="wrap">
+ <div class="landing-section-header">
+ <div class="landing-h1">Get Your Apps Ready</div>
+ <div class="landing-subhead">
+ <p>We're giving you an early look at the SDK, so you can test your apps and build in new features.</p>
+ </div>
+ </div>
+ <div class="landing-body">
+ <p>You'll get the system images for the Nexus 5, Nexus 7 (v2),
+ and the emulator to take the new platform for a spin. In addition, you'll have
+ access to all the APIs with a preview build of the SDK.
+ </p>
+
+ <p>Check out the getting started, developer guides, and reference documentation
+ for all the information you need to get up and running.</p>
+
+ <a href="/preview/setup-sdk.html" class="landing-button landing-secondary" style="margin-top: 20px;">
+ Get Started
+ </a>
+ </div>
+ </div>
+ </div>
+ <div class="landing-section">
+ <div class="wrap">
+ <div class="cols">
+ <div class="landing-body">
+ <div class="col-3-wide">
+ <a target="_blank" href="http://submit-bugs!">
+ <img class="landing-social-image" src="{@docRoot}preview/images/bugs.png" alt="">
+ </a>
+ <div class="landing-social-copy">
+ <p>Issue Tracker</p>
+ <p class="landing-small">
+ Let us know when you encounter problems, so we can fix them and make
+ the platform better for you and your users.
+ </p><p class="landing-small">
+ <a target="_blank" href="http://submit-bugs!">
+ Report Issues</a>
+ </p>
+ <p></p>
+ </div>
+ </div>
+ <div class="col-3-wide">
+ <a target="_blank" href="http://plus.google.com">
+ <img class="landing-social-image" src="//www.google.com/images/icons/product/gplus-128.png" alt="">
+ </a>
+ <div class="landing-social-copy">
+ <p>Google+ </p>
+ <p class="landing-small">
+ Join the community of Android developers testing out the L Developer Preview and
+ share your thoughts and experiences.
+ </p><p class="landing-small">
+ <a target="_blank" href="http://plus.google.com">
+ Discuss on Google+</a>
+ </p>
+ </div>
+ </div>
+ <div class="col-3-wide">
+ <a target="_blank" href="{@docRoot}preview/release-notes.html">
+ <img class="landing-social-image" src="{@docRoot}preview/images/updates.png" alt="">
+ </a>
+ <div class="landing-social-copy">
+ <p>Support and Updates</p>
+ <p class="landing-small">
+ Updates to the L Developer Preview are delivered
+ in the Android SDK Manager. Check back periodically
+ for news about the changes.
+ </p>
+ <p class="landing-small">
+ <a target="_blank" href="{@docRoot}preview/support.html">Get Support</a>
+ </p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div> <!-- end .wrap -->
+ </div>
+
+ <div class="content-footer wrap" itemscope="" itemtype="http://schema.org/SiteNavigationElement">
+ <div class="layout-content-col col-16" style="padding-top:4px">
+ <style>#___plusone_0 {float:right !important;}</style>
+ <div class="g-plusone" data-size="medium"></div>
+ </div>
+ </div>
+ <div id="footer" class="wrap" style="width:940px;position:relative;top:-35px;z-index:-1">
+ <div id="copyright">
+ Except as noted, this content is
+ licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
+ Creative Commons Attribution 2.5</a>. For details and
+ restrictions, see the <a href="/license.html">Content
+ License</a>.
+ </div>
+ </div>
+ </div> <!-- end landing-body-content -->
+
+ <script>
+ $("a.landing-down-arrow").on("click", function(e) {
+ $("body").animate({
+ scrollTop: $(".preview-hero").height() + 76
+ }, 1000, "easeOutQuint");
+ e.preventDefault();
+ });
+ </script>
\ No newline at end of file
diff --git a/docs/html/preview/material/animations.jd b/docs/html/preview/material/animations.jd
new file mode 100644
index 0000000..cee782a
--- /dev/null
+++ b/docs/html/preview/material/animations.jd
@@ -0,0 +1,378 @@
+page.title=Animations
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+ <li><a href="#touch">Touch Feedback</a></li>
+ <li><a href="#reveal">Reveal Effect</a></li>
+ <li><a href="#transitions">Activity Transitions</a></li>
+ <li><a href="#curvedmotion">Curved Motion</a></li>
+ <li><a href="#viewstate">View State Changes</a></li>
+ <li><a href="#drawabletint">Drawable Tinting</a></li>
+</ol>
+</div>
+</div>
+
+<p>Animations in material design give users feedback on their actions and provide visual
+continuity as users interact with your app. The material theme provides some default animations
+for buttons and activity transitions, and the Android L Developer Preview provides additional
+APIs that let you customize these animations and create new ones:</p>
+
+<ul>
+<li>Touch feedback</li>
+<li>Reveal effect</li>
+<li>Activity transitions</li>
+<li>Curved motion</li>
+<li>View state changes</li>
+</ul>
+
+
+<h2 id="touch">Touch Feedback</h2>
+
+<p>In the Android L Developer Preview the default touch feedback animations for buttons use the new
+<code>RippleDrawable</code> class, which transitions between different states with a ripple
+effect.</p>
+
+<p>To use this functionality in your custom views, create a <code>RippleDrawable</code> and set
+it as the background of your view. You can define a <code>RippleDrawable</code> as an XML resource
+using the <code>ripple</code> element.</p>
+
+
+<h2 id="reveal">Reveal Effect</h2>
+
+<p>The <code>View.createRevealAnimator</code> method enables you to animate a clipping circle
+to reveal or hide a view.</p>
+
+<p>To reveal a previously invisible view using this effect:</p>
+
+<pre>
+// previously invisible view
+View myView = findViewById(R.id.my_view);
+
+// get the center for the clipping circle
+int cx = (myView.getLeft() + myView.getRight()) / 2;
+int cy = (myView.getTop() + myView.getBottom()) / 2;
+
+// get the final radius for the clipping circle
+int finalRadius = myView.getWidth();
+
+// create and start the animator for this view
+// (the start radius is zero)
+ValueAnimator anim = myView.createRevealAnimator(cx, cy, 0, finalRadius);
+anim.start();
+</pre>
+
+<p>To hide a previously visible view using this effect:</p>
+
+<pre>
+// previously visible view
+final View myView = findViewById(R.id.my_view);
+
+// get the center for the clipping circle
+int cx = (myView.getLeft() + myView.getRight()) / 2;
+int cy = (myView.getTop() + myView.getBottom()) / 2;
+
+// get the initial radius for the clipping circle
+int initialRadius = myView.getWidth();
+
+// create the animation (the final radius is zero)
+ValueAnimator anim = myView.createRevealAnimator(cx, cy, initialRadius, 0);
+
+// make the view invisible when the animation is done
+anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ myView.setVisibility(View.INVISIBLE);
+ }
+});
+
+// start the animation
+anim.start();
+</pre>
+
+
+<h2 id="transitions">Activity Transitions</h2>
+
+<p>The Android L Developer Preview enables your app to customize the default animations for
+activity transitions. You can specify custom animations for enter and exit transitions and for
+transitions of shared elements between activities.</p>
+
+<ul>
+ <li>An <strong>enter</strong> transition determines how views in an activity enter the scene.
+ For example, in the <em>explode</em> enter transition the views enter the scene from outside
+ and fly in towards the center of the screen.</li>
+
+ <li>An <strong>exit</strong> transition determines how views in an activity exit the scene. For
+ example, in the <em>explode</em> exit transition the views exit the scene away from the
+ center.</li>
+
+ <li>A <strong>shared elements</strong> transition determines how views that are shared between
+ two activities transition between these activities. For example, if two activities have the same
+ image in different positions and sizes, the <em>moveImage</em> shared element transition
+ translates and scales the image smoothly between these activities.</li>
+</ul>
+
+<img src="/preview/material/images/SceneTransition.png" alt=""
+ id="figure1" style="width:600px;margin-top:20px"/>
+<p class="img-caption">
+ <strong>Figure 1</strong> - A scene transition with one shared element.
+</p>
+
+<h3>Specify custom transitions</h3>
+
+<p>First, enable window content transitions with the <code>android:windowContentTransitions</code>
+attribute when you define a style that inherits from the material theme:</p>
+
+<pre>
+<style name="BaseAppTheme" parent="android:Theme.Material">
+ <!-- enable window content transitions -->
+ <item name="android:windowContentTransitions">true</item>
+
+ <!-- specify enter and exit transitions -->
+ <item name="android:windowEnterTransition">@transition/explode</item>
+ <item name="android:windowExitTransition">@transition/explode</item>
+
+ <!-- specify shared element transitions -->
+ <item name="android:windowSharedElementEnterTransition">
+ @transition/move_image</item>
+ <item name="android:windowSharedElementExitTransition">
+ @transition/move_image</item>
+</style>
+</pre>
+
+<p>You can also specify enter, exit, and shared element transitions in your style definition.
+The <code>move_image</code> transition in this example is defined as follows:</p>
+
+<pre>
+<!-- res/transition/move_image.xml -->
+<!-- (see also Shared Transitions below) -->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+ <moveImage>
+ <targets>
+ <!-- shared view in the first activity -->
+ <target android:targetId="@id/image_small" />
+ <!-- shared view in the second activity -->
+ <target android:targetId="@id/image_big" />
+ </targets>
+ </moveImage>
+</transitionSet>
+</pre>
+
+<p>The <code>moveImage</code> element corresponds to the <code>android.transition.MoveImage</code>
+class. For more information, see the API reference for <code>android.transition.Transition</code>.
+</p>
+
+<p>To enable window content transitions in your code instead, call the
+<code>Window.requestFeature</code> method:</p>
+
+<pre>
+// inside your activity
+getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
+
+// set an exit transition
+getWindow().setExitTransition(new Explode());
+</pre>
+
+<p>To specify transitions in your code, call these methods with a <code>Transition</code>
+object:</p>
+
+<ul>
+ <li><code>Window.setEnterTransition</code></li>
+ <li><code>Window.setExitTransition</code></li>
+ <li><code>Window.setSharedElementEnterTransition</code></li>
+ <li><code>Window.setSharedElementExitTransition</code></li>
+</ul>
+
+<h3>Start an activity using transitions</h3>
+
+<p>If you enable transitions and set an exit transition for an activity, the transition is activated
+when you launch another activity with the <code>startActivity</code> method. If you have set an
+enter transition for the second activity, the transition is also activated when the activity
+starts.</p>
+
+<h3>Shared elements transitions</h3>
+
+<p>To make a screne transition animation between two activities that have a shared element:</p>
+
+<ol>
+<li>Enable window content transitions in your style.</li>
+<li>Specify a shared elements transition in your style.</li>
+<li>Define your transition as an XML resource specifying the IDs of the target views.</li>
+<li>Assign a common name to the shared elements in both layouts with the
+ <code>android:viewName</code> attribute.</li>
+<li>Use the <code>ActivityOptions.makeSceneTransitionAnimation</code> method.</li>
+</ol>
+
+<pre>
+// get the element that receives the click event
+final View imgContainerView = findViewById(R.id.img_container);
+
+// get the common element for the transition in this activity
+final View androidRobotView = findViewById(R.id.android_robot_img);
+
+// define a click listener
+imgContainerView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Intent intent = new Intent(this, Activity2.class);
+ // create the transition animation - the images in the layouts
+ // of both activities are defined with android:viewName="robot"
+ ActivityOptions options = ActivityOptions
+ .makeSceneTransitionAnimation(this, androidRobotView, "robot");
+ // start the new activity
+ startActivity(intent, options.toBundle());
+ }
+});
+</pre>
+
+<p>For shared dynamic views that you generate in your code, use the <code>View.setViewName</code>
+method to specify a common element name in both activities.</p>
+
+<h3>Multiple shared elements</h3>
+
+<p>To make a scene transition animation between two activities that have more than one shared
+element, define the shared elements in both layouts with the <code>android:viewName</code>
+attribute (or use the <code>View.setViewName</code> in both activities), and create an
+<code>ActivityOptions</code> object as follows:</p>
+
+<pre>
+ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
+ new Pair[] {
+ Pair.create(view1, "agreedName1"),
+ Pair.create(view2, "agreedName2"),
+ ...
+ }
+);
+</pre>
+
+
+<h2 id="curvedmotion">Curved Motion</h2>
+
+<p>Animations in material design rely on curves for time interpolation and spatial movement
+patterns. The Android L Developer Preview provides new APIs that enable you to define custom
+timing curves and curved motion patterns for animations.</p>
+
+<p>The <code>PathInterpolator</code> class is a new interpolator based on a Bézier curve or a
+<code>Path</code> object. This interpolator specifies a motion curve in a 1x1 square, with anchor
+points at (0,0) and (1,1) and control points as specified using the constructor arguments. You can
+also define a <code>PathInterpolator</code> as an XML resource:</p>
+
+<pre>
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.4"
+ android:controlY1="0"
+ android:controlX2="1"
+ android:controlY2="1"/>
+</pre>
+
+<p>The Android L Developer Preview provides XML resources for the three basic curves in the
+material design specification:</p>
+
+<ul>
+ <li><code>@interpolator/fast_out_linear_in.xml</code></li>
+ <li><code>@interpolator/fast_out_slow_in.xml</code></li>
+ <li><code>@interpolator/linear_out_slow_in.xml</code></li>
+</ul>
+
+<p>You can pass a <code>PathInterpolator</code> object to the
+<code>Animation.setInterpolation</code> method.</p>
+
+<p>The <code>ObjectAnimator</code> class has new constructors that enable you to animate
+coordinates along a path using two or more properties at once. For example, the following animator
+uses a <code>Path</code> object to animate the X and Y properties of a view:</p>
+
+<pre>
+ObjectAnimator mAnimator;
+mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
+...
+mAnimator.start();
+</pre>
+
+
+<h2 id="viewstate">View State Changes</h2>
+
+<p>The new <code>StateListAnimator</code> class lets you define animators that run when the state
+of a view changes. The following example shows how to define an <code>StateListAnimator</code> as
+an XML resource:</p>
+
+<pre>
+<!-- animate the elevation property of a view when pressed -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true">
+ <set>
+ <objectAnimator android:propertyName="elevation"
+ android:duration="100"
+ android:valueTo="60"
+ android:valueType="floatType"/>
+ <!-- you could have other objectAnimator elements
+ here for "x" and "y", or other properties -->
+ </set>
+ </item>
+ <item android:state_enabled="true"
+ android:state_pressed="false"
+ android:state_focused="true">
+ <set>
+ <objectAnimator android:propertyName="elevation"
+ android:duration="100"
+ android:valueTo="10"
+ android:valueType="floatType"/>
+ </set>
+ </item>
+</selector>
+</pre>
+
+<p>The new <code>AnimatedStateListDrawable</code> class lets you create drawables that show
+animations between state changes of the associated view. Some of the system widgets in the
+Android L Developer Preview use these animations by default. The following example shows how
+to define an <code>AnimatedStateListDrawable</code> as an XML resource:</p>
+
+<pre>
+<!-- res/drawable/myanimstatedrawable.xml -->
+<animated-selector
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <!-- provide a different drawable for each state-->
+ <item android:id="@+id/pressed" android:drawable="@drawable/drawableP"
+ android:state-pressed="true"/>
+ <item android:id="@+id/focused" android:drawable="@drawable/drawableF"
+ android:state-focused="true"/>
+ <item android:id="@id/default"
+ android:drawable="@drawable/drawableD"/>
+
+ <!-- specify a transition -->
+ <transition android:fromId="@+id/default" android:toId="@+id/pressed">
+ <animation-list>
+ <item android:duration="15" android:drawable="@drawable/dt1"/>
+ <item android:duration="15" android:drawable="@drawable/dt2"/>
+ ...
+ </animation-list>
+ </transition>
+ ...
+</animated-selector>
+</pre>
+
+
+<h2 id="drawabletint">Drawable Tinting</h2>
+
+<p>The Android L Developer Preview enables you to define bitmaps as an alpha mask and to tint
+them using a color resource or a theme attribute that resolves to a color resource. You can
+create these assets only once and color them automatically to match your theme.</p>
+
+<p>To apply a tint to a bitmap in your code, use the <code>setTint</code> method in these
+classes:</p>
+
+<ul>
+<li><code>PaintDrawable</code></li>
+<li><code>NinePatchDrawable</code></li>
+<li><code>RippleDrawable</code></li>
+</ul>
+
+<p>In your layouts, use the <code>android:tint</code> attribute instead.</p>
+
+<p>The <code>setTint</code> method also lets you set the tint blending mode for
+<code>NinePatchDrawable</code> and <code>RippleDrawable</code> objects in your code. To set the
+tint mode in your layouts, use the <code>android:tintMode</code> attribute.</p>
diff --git a/docs/html/preview/material/compatibility.jd b/docs/html/preview/material/compatibility.jd
new file mode 100644
index 0000000..ce04e9e
--- /dev/null
+++ b/docs/html/preview/material/compatibility.jd
@@ -0,0 +1,63 @@
+page.title=Compatibility
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+ <li><a href="#materialtheme">Material Theme</a></li>
+ <li><a href="#layouts">Layouts</a></li>
+ <li><a href="#widgets">UI Widgets</a></li>
+ <li><a href="#animation">Animation APIs</a></li>
+</ol>
+</div>
+</div>
+
+<p>The new material design features (like the material theme and custom animations) are only
+available in the Android L Developer Preview. However, you can design your apps to make use of
+these features when running on devices with the Android L Developer Preview and still be
+compatible with previous releases of Android.</p>
+
+
+<h2 id="materialtheme">Material Theme</h2>
+
+<p>The material theme is only available in the Android L Developer Preview. To configure your
+app to use the material theme on devices running the Android L Developer Preview and an older
+theme on devices running earlier versions of Android:</p>
+
+<ol>
+<li>Define a theme that inherits from an older theme (like Holo) in
+<code>res/values/styles.xml</code>.</li>
+<li>Define a theme with the same name that inherits from the material theme in
+<code>res/values-v21/styles.xml</code>.</li>
+<li>Set this theme as your app's theme in the manifest file.</li>
+</ol>
+
+<p class="note"><strong>Note:</strong> If you do not provide an alternative theme in this manner,
+your app will not run on earlier versions of Android.</p>
+
+
+<h2 id="layouts">Layouts</h2>
+
+<p>If the layouts that you design according to the material design guidelines do not use any
+of the new XML attributes from the Android L Developer Preview, they will work on previous
+versions of Android. Otherwise, you can provide alternative layouts. You can also provide
+alternative layouts to customize how your app looks on earlier versions of Android.</p>
+
+<p>Create your layout files for the Android L Developer Preview inside <code>res/layout-v21/</code>
+and your alternative layout files for earlier versions of Android inside <code>res/layout/</code>.
+Alternative layouts have the same file name.</p>
+
+
+<h2 id="widgets">UI Widgets</h2>
+
+<p>The <code>RecyclerView</code> and <code>CardView</code> widgets are included in the Android L
+Developer Preview Support Library, so they are available in earlier versions of Android.</p>
+
+
+<h2 id="animation">Animation APIs</h2>
+
+<p>The new APIs for custom animations are only available in the Android L Developer Preview. To
+preserve compatibility with earlier verisons of Android, check the system version at runtime before
+you invoke these APIs.</p>
\ No newline at end of file
diff --git a/docs/html/preview/material/get-started.jd b/docs/html/preview/material/get-started.jd
new file mode 100644
index 0000000..9c0e55d
--- /dev/null
+++ b/docs/html/preview/material/get-started.jd
@@ -0,0 +1,146 @@
+page.title=Get Started
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+ <li><a href="#applytheme">Apply the Material Theme</a></li>
+ <li><a href="#layouts">Design Your Layouts</a></li>
+ <li><a href="#depth">Specify Depth in Your Views</a></li>
+ <li><a href="#widgets">Use the New UI Widgets</a></li>
+ <li><a href="#apis">Use the New APIs</a></li>
+</ol>
+</div>
+</div>
+
+<p>To create apps with material design:</p>
+
+<ol>
+ <li style="margin-bottom:10px">
+ Take a look at the <a href="">material design specification</a>.</li>
+ <li style="margin-bottom:10px">
+ Apply the material <strong>theme</strong> to your app.</li>
+ <li style="margin-bottom:10px">
+ Define additional <strong>styles</strong> to customize the material theme.</li>
+ <li style="margin-bottom:10px">
+ Create your <strong>layouts</strong> following material design guidelines.</li>
+ <li style="margin-bottom:10px">
+ Specify the <strong>depth</strong> for views to cast appropriate shadows.</li>
+ <li style="margin-bottom:10px">
+ Use the new <strong>widgets</strong> for complex views, such as lists and cards.</li>
+ <li style="margin-bottom:10px">
+ Use the new <strong>APIs</strong> to customize the animations in your app.</li>
+</ol>
+
+<h3>Update Your App for the Android L Developer Preview</h3>
+
+<p>To update an existing app for the Android L Developer Preview, design new layouts following
+material design guidelines and consider how you can improve the user experience for your app by
+incorporating depth, touch feedback and animations in your UI.</p>
+
+<h3>Create New Apps for the Android L Developer Preview</h3>
+
+<p>If you are creating a new app for the Android L Developer Preview, the material design
+guidelines provide you with a solid design framework for your app. Follow these guidelines and
+use the new functionality in the Android framework to design and develop your app.</p>
+
+
+<h2 id="applytheme">Apply the Material Theme</h2>
+
+<p>To apply the material theme in your app, specify a style that inherits from
+<code>android:theme.Material</code>:</p>
+
+<pre>
+<!-- res/values/styles.xml -->
+<resources>
+ <!-- your app's theme inherits from the Material theme -->
+ <style name="AppTheme" parent="android:Theme.Material">
+ <!-- theme customizations -->
+ </style>
+</resources>
+</pre>
+
+<p>The material theme provides new system widgets that let you set their color palette and default
+animations for touch feedback and activity transitions. For more details, see
+<a href="{@docRoot}preview/material/theme.html">Material Theme</a>.</p>
+
+
+<h2 id="layouts">Design Your Layouts</h2>
+
+<p>In addition to applying and customizing the material theme, your layouts should conform to
+the material design guidelines. When you design your layouts, pay special attention to the
+following:</p>
+
+<ul>
+<li>Baseline grids</li>
+<li>Keylines</li>
+<li>Spacing</li>
+<li>Touch target size</li>
+<li>Layout structure</li>
+</ul>
+
+<p>You still define layouts inside XML files using the standard tools from the Android framework.
+For details on the material design guidelines, see the <a href="">material design
+specification</a>.</p>
+
+
+<h2 id="depth">Specify Depth in Your Views</h2>
+
+<p>In the Android L Developer Preview, views can cast shadows. The elevation value of a view
+determines the size of its shadow. To set the elevation of a view, use the
+<code>android:elevation</code> attribute in your layouts:</p>
+
+<pre>
+<Button
+ android:id="@+id/my_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/next"
+ <strong>android:elevation</strong>="10dp" />
+</pre>
+
+<p>For more details, see <a href="{@docRoot}preview/material/views-shadows.html">Views and
+Shadows</a>.</p>
+
+
+<h2 id="widgets">Use the New UI Widgets</h2>
+
+<p>The Android L Developer Preview includes two new UI widgets for complex views,
+<code>RecyclerView</code> and <code>CardView</code>. <code>RecyclerView</code> is a more advanced
+version of <code>ListView</code> that provides performance improvements and is easier to use.
+<code>CardView</code> lets you show pieces of information inside cards with a consistent look
+across apps. To include a <code>CardView</code> in your layout:</p>
+
+<pre>
+<android.support.v7.widget.CardView
+ android:id="@+id/card_view"
+ android:layout_width="200dp"
+ android:layout_height="200dp"
+ card_view:cardCornerRadius="3dp">
+ ...
+</android.support.v7.widget.CardView>
+</pre>
+
+<p>For more information, see <a href="{@docRoot}preview/material/ui-widgets.html">UI Widgets</a>.</p>
+
+
+<h2 id="apis">Use the APIs to Customize Your Animations</h2>
+
+<p>The Android L Developer Preview includes new APIs to create custom animations in your app.
+For example, you can enable activity transitions and define an exit transition inside an
+activity:</p>
+
+<pre>
+// inside your activity
+getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
+
+// set an exit transition
+getWindow().setExitTransition(new Explode());
+</pre>
+
+<p>When you start another activity from this activity, the exit transition is activated.</p>
+
+<p>To learn about all the features in the new APIs, see <a
+href="{@docRoot}preview/material/animations.html">Animations</a>.</p>
\ No newline at end of file
diff --git a/docs/html/preview/material/images/MaterialDark.png b/docs/html/preview/material/images/MaterialDark.png
new file mode 100644
index 0000000..6a72280
--- /dev/null
+++ b/docs/html/preview/material/images/MaterialDark.png
Binary files differ
diff --git a/docs/html/preview/material/images/MaterialLight.png b/docs/html/preview/material/images/MaterialLight.png
new file mode 100644
index 0000000..0e85528
--- /dev/null
+++ b/docs/html/preview/material/images/MaterialLight.png
Binary files differ
diff --git a/docs/html/preview/material/images/RecyclerView.png b/docs/html/preview/material/images/RecyclerView.png
new file mode 100644
index 0000000..364951d
--- /dev/null
+++ b/docs/html/preview/material/images/RecyclerView.png
Binary files differ
diff --git a/docs/html/preview/material/images/SceneTransition.png b/docs/html/preview/material/images/SceneTransition.png
new file mode 100644
index 0000000..ecaf472
--- /dev/null
+++ b/docs/html/preview/material/images/SceneTransition.png
Binary files differ
diff --git a/docs/html/preview/material/images/ThemeColors.png b/docs/html/preview/material/images/ThemeColors.png
new file mode 100644
index 0000000..bbcecf2
--- /dev/null
+++ b/docs/html/preview/material/images/ThemeColors.png
Binary files differ
diff --git a/docs/html/preview/material/images/card_travel.png b/docs/html/preview/material/images/card_travel.png
new file mode 100644
index 0000000..a804ca0
--- /dev/null
+++ b/docs/html/preview/material/images/card_travel.png
Binary files differ
diff --git a/docs/html/preview/material/images/list_mail.png b/docs/html/preview/material/images/list_mail.png
new file mode 100644
index 0000000..ca53ee1
--- /dev/null
+++ b/docs/html/preview/material/images/list_mail.png
Binary files differ
diff --git a/docs/html/preview/material/index.jd b/docs/html/preview/material/index.jd
new file mode 100644
index 0000000..b7abcb4
--- /dev/null
+++ b/docs/html/preview/material/index.jd
@@ -0,0 +1,117 @@
+page.title=Material Design
+page.type=design
+
+@jd:body
+
+<p itemprop="description">The Android L Developer Preview includes support for material design apps. Material design
+is a comprehensive guide for visual, motion, and interaction design across platforms and devices.
+To use material design in your Android apps, follow the guidelines defined in the
+<a href="">material design specification</a> and use the new components and functionality
+available in the Android L Developer Preview.</p>
+
+<p>The Android L Developer Preview provides the following elements for you to build material
+design apps:</p>
+
+<ul>
+ <li>A new theme</li>
+ <li>New widgets for complex views</li>
+ <li>New APIs for custom shadows and animations</li>
+</ul>
+
+
+<h3>Material Theme</h3>
+
+<p>The material theme provides a new style for your app, system widgets that let you set
+their color palette, and default animations for touch feedback and activity transitions.</p>
+
+<!-- two columns -->
+<div style="width:700px;margin-top:25px;margin-bottom:20px">
+<div style="float:left;width:250px;margin-left:40px;margin-right:60px;">
+ <img src="{@docRoot}preview/material/images/MaterialDark.png" style="width:250px;"/>
+ <div style="width:140px;margin:0 auto">
+ <p style="margin-top:8px">Dark Material theme</p>
+ </div>
+</div>
+<div style="float:left;width:250px;margin-right:0px;">
+ <img src="{@docRoot}preview/material/images/MaterialLight.png" style="width:250px;"/>
+ <div style="width:140px;margin:0 auto">
+ <p style="margin-top:8px">Light Material theme</p>
+ </div>
+</div>
+<br style="clear:left"/>
+</div>
+
+
+<h3>New Widgets</h3>
+
+<p>The Android L Developer Preview includes two new widgets for displaying complex views:</p>
+
+<!-- two columns -->
+<div style="width:700px;margin-top:25px;margin-bottom:20px">
+<div style="float:left;width:250px;margin-left:40px;margin-right:60px;">
+ <img src="{@docRoot}preview/material/images/list_mail.png" style="width:250px;"/>
+ <p>The new <code>RecyclerView</code> widget is a more advanced version of <code>ListView</code>
+ provides performance improvements for dynamic views and is easier to use.</p>
+</div>
+<div style="float:left;width:250px;margin-right:0px;">
+ <img src="{@docRoot}preview/material/images/card_travel.png" style="width:250px;"/>
+ <p>The new <code>CardView</code> widget lets you display important pieces of information inside
+ cards that have a consistent look and feel.</p>
+</div>
+<br style="clear:left"/>
+</div>
+
+
+<h3>View Shadows</h3>
+
+<p>In addition to the X and Y components, views in the Android L Developer Preview have a Z
+component. This new component represents the elevation of a view, which determines the size of
+its shadow: views with higher Z values cast bigger shadows.</p>
+
+<div style="width:290px;margin-left:35px;float:right">
+ <div class="framed-nexus5-port-span-5">
+ <video class="play-on-hover" autoplay>
+ <source src="/preview/material/videos/ContactsAnim.mp4"/>
+ <source src="/preview/material/videos/ContactsAnim.webm"/>
+ <source src="/preview/material/videos/ContactsAnim.ogv"/>
+ </video>
+ </div>
+ <div style="font-size:10pt;margin-left:20px;margin-bottom:30px">
+ <em>Click on the device screen to replay the movie</em>
+ </div>
+</div>
+
+<h3>Animations</h3>
+
+<p>The Android L Developer Preview provides new APIs that let you create custom animations for
+touch feedback in UI controls, view state changes, and activity transitions.</p>
+
+<p>The new animation APIs in the Android L Developer Preview let you:</p>
+
+<ul>
+<li style="margin-bottom:15px">
+Respond to touch events in your views with <strong>touch feedback</strong> animations.
+</li>
+<li style="margin-bottom:15px">
+Hide and show views with <strong>reveal effect</strong> animations.
+</li>
+<li style="margin-bottom:15px">
+Switch between activities with custom <strong>activity transition</strong> animations.
+</li>
+<li style="margin-bottom:15px">
+Create custom animation patterns with <strong>curved motion</strong>.
+</li>
+<li style="margin-bottom:15px">
+Animate changes in one or more view properties with <strong>view state change</strong> animations.
+</li>
+<li style="margin-bottom:15px">
+Show animations in <strong>state list drawables</strong> between view state changes.
+</li>
+</ul>
+
+
+<h3>New Capabilities for Drawables</h3>
+
+<p>The Android L Developer Preview supports <strong>drawable tinting</strong>: you can define
+bitmaps as an alpha mask and tint them using a color resource. You can create these assets only
+once and color each instance to match your theme.</p>
diff --git a/docs/html/preview/material/theme.jd b/docs/html/preview/material/theme.jd
new file mode 100644
index 0000000..b954960
--- /dev/null
+++ b/docs/html/preview/material/theme.jd
@@ -0,0 +1,100 @@
+page.title=Material Theme
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+ <li><a href="#colorpalette">Customize the Colot Palette</a></li>
+ <li><a href="#statusbar">Customize the Status Bar</a></li>
+ <li><a href="#inheritance">Theme Inheritance</a></li>
+</ol>
+</div>
+</div>
+
+<p>The new material theme provides:</p>
+
+<ul>
+ <li>System widgets that let you set their color palette</li>
+ <li>Touch feedback animations for the system widgets</li>
+ <li>Activity transition animations</li>
+</ul>
+
+<p>The Android L Developer Preview lets you easily customize the look of the material theme
+according to your brand identity with a color palette you control. You can tint the app bar and
+the status bar using theme attributes, as shown in Figure 1.</p>
+
+<div style="float:right;margin-left:25px;margin-top:-25px">
+<img src="{@docRoot}preview/material/images/ThemeColors.png" style="width:250px"/>
+<p class="img-caption"><strong>Figure 1.</strong> Customizing the material theme.</p>
+</div>
+
+<p>The system widgets have a new design and touch feedback animations. Activity transitions help
+users navigate your app by providing visual continuity. You can customize the color palette,
+the touch feedback animations, and the activity transitions for your app.</p>
+
+<p>The material theme is defined as:</p>
+
+<ul>
+ <li><code>@android:style/Theme.Material</code> (dark version)</li>
+ <li><code>@android:style/Theme.Material.Light</code> (light version)</li>
+ <li><code>@android:style/Theme.Material.Light.DarkActionBar</code></li>
+</ul>
+
+<p>For a list of material styles that you can use, see the API reference for
+<code>android.R.styles</code>.</p>
+
+<p class="note">
+<strong>Note:</strong> The material theme is only available in the Android L Developer Preview.
+For more information, see <a href="{@docRoot}preview/material/compatibility.html">Compatibility</a>.
+</p>
+
+
+<h2 id="colorpalette">Customize the Color Palette</h2>
+
+<p>To customize the theme's base colors to fit your brand, define your custom colors using
+theme attributes when you inherit from the material theme:</p>
+
+<pre>
+<resources>
+ <!-- inherit from the material theme -->
+ <style name="AppTheme" parent="android:Theme.Material">
+ <!-- Main theme colors -->
+ <!-- your app's branding color (for the app bar) -->
+ <item name="android:colorPrimary">@color/primary</item>
+ <!-- darker variant of colorPrimary (for contextual app bars) -->
+ <item name="android:colorPrimaryDark">@color/primary_dark</item>
+
+ <!-- other theme colors -->
+ <item name="android:colorButtonNormal">@color/button_normal</item>
+ <item name="android:windowBackground">@color/wbackground</item>
+ </style>
+</resources>
+</pre>
+
+
+<h2 id="statusbar">Customize the Status Bar</h2>
+
+<p>The material theme lets you easily customize the status bar, so you can specify a
+color which fits your brand and provides enough contrast to show the white status icons. To
+set a custom color for the status bar, use the <code>android:statusBarColor</code> attribute when
+you extend the material theme.</p>
+
+<p>To handle the color of the status bar yourself (for example, by adding a gradient in the
+background), set the <code>android:statusBarColor</code> attribute to
+<code>@android:color/transparent</code>. You can also use the
+<code>Window.setStatusBarColor</code> method for animations or fading.</p>
+
+<p class="note"><strong>Note:</strong>
+The status bar should almost always have a clear delineation from the primary toolbar, except for
+full-bleed imagery cases and when you use a gradient as a protection.
+</p>
+
+
+<h2 id="inheritance">Theme Inheritance</h3>
+
+<p>In the Android L Developer Preview, elements in XML layout definitions can specify the
+<code>android:theme</code> attribute, which references a theme resource. This attribute modifies
+the theme for the element and any elements inflated below it, which is useful to alter theme
+color palettes in a specific portion of an interface.</p>
\ No newline at end of file
diff --git a/docs/html/preview/material/ui-widgets.jd b/docs/html/preview/material/ui-widgets.jd
new file mode 100644
index 0000000..f18bff9
--- /dev/null
+++ b/docs/html/preview/material/ui-widgets.jd
@@ -0,0 +1,197 @@
+page.title=UI Widgets
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+ <li><a href="#recyclerview">RecyclerView</a></li>
+ <li><a href="#cardview">CardView</a></li>
+</ol>
+</div>
+</div>
+
+<p>The support library in the Android L Developer Preview contains two new widgets,
+<code>RecyclerView</code> and <code>CardView</code>. Use these widgets to show complex lists
+and cards in your app. These widgets have material design styles and animations by default.</p>
+
+
+<h2 id="recyclerview">RecyclerView</h2>
+
+<p><code>RecyclerView</code> is a more advanced version of <code>ListView</code>. This widget is
+a container for large sets of views that can be recycled and scrolled very efficiently. Use the
+<code>RecyclerView</code> widget when you have lists with elements that change dynamically.</p>
+
+<p><code>RecyclerView</code> is easy to use, because it provides:</p>
+
+<ul>
+ <li>A set of layout managers for positioning items</li>
+ <li>Default animations for common item operations</li>
+</ul>
+
+<p>You also have the flexibility to define custom layout managers and animations for this
+widget.</p>
+
+<p>To use the <code>RecyclerView</code> widget, you have to specify an adapter and a layout
+manager. An <strong>adapter</strong> provides a binding from a dataset to views that are displayed
+within a <code>RecyclerView</code>. For example, if your dataset is an array of strings displayed
+as <code>TextView</code> items, the layout manager asks the adapter to:
+</p>
+
+<ul>
+ <li>Set the text of an existing <code>TextView</code> to one of the strings in the dataset</li>
+ <li>Create new <code>TextView</code> objects</li>
+ <li>Determine the size of the dataset</li>
+</ul>
+
+<p>To create an adapter, you extend the <code>RecyclerView.Adapter</code> class. The details of
+the implementation depend on the specifics of your dataset and the type of views. Fore more
+information, see the examples below.</p>
+
+<img src="/preview/material/images/RecyclerView.png" alt="" id="figure1" style="width:550px"/>
+<p class="img-caption">
+ <strong>Figure 1</strong> - The <code>RecyclerView</code> widget.
+</p>
+
+<p>A <strong>layout manager</strong> positions item views inside a <code>RecyclerView</code> and
+determines when to reuse item views that are no longer visible to the user. To reuse (or
+<em>recycle</em>) a view, a layout manager may ask the adapter to replace the content of the
+view with a different element from the dataset. Recycling views in this manner improves
+performance by avoiding the creation of unnecessary views or performing expensive
+<code>findViewById</code> lookups.
+</p>
+
+<p><code>RecyclerView</code> provides two layout managers you can use:</p>
+
+<ul>
+ <li><code>LinearLayoutManager</code> shows the items in a vertically scrolling list.</li>
+ <li><code>GridLayoutManager</code> shows the items in a rectangular grid.</li>
+</ul>
+
+<p>To create a custom layout, you extend the <code>RecyclerView.LayoutManager</code> class.</p>
+
+<h3>Examples</h3>
+
+<p>To include a <code>RecyclerView</code> in your layout:</p>
+
+<pre>
+<!-- A RecyclerView with some commonly used attributes -->
+<android.support.v7.widget.RecyclerView
+ android:id="@+id/my_recycler_view"
+ android:scrollbars="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</pre>
+
+<p>To get the <code>RecyclerView</code> object in your activity:</p>
+
+<pre>
+public class MyActivity extends ActionBarActivity {
+ private RecyclerView mRecyclerView;
+ private RecyclerView.Adapter mAdapter;
+ private RecyclerView.LayoutManager mLayoutManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.my_activity);
+ mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
+
+ // improve performance if the size is fixed
+ mRecyclerView.setHasFixedSize(true);
+
+ // use a linear layout manager
+ mLayoutManager = new LinearLayoutManager(this);
+ mRecyclerView.setLayoutManager(mLayoutManager);
+
+ // specify an adapter (see also next example)
+ mAdapter = new MyAdapter(myDataset);
+ mRecyclerView.setAdapter(mAdapter);
+ }
+ ...
+}
+</pre>
+
+<p>To create a simple adapter:</p>
+
+<pre>
+public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
+ private String[] mDataset;
+
+ // Provide a reference to the type of views that you are using
+ // (custom viewholder)
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+ public TextView mTextView;
+ public ViewHolder(TextView v) {
+ super(v);
+ mTextView = v;
+ }
+ }
+
+ // Provide a suitable constructor (depends on the kind of dataset)
+ public MyAdapter(String[] myDataset) {
+ mDataset = myDataset;
+ }
+
+ // Create new views (invoked by the layout manager)
+ @Override
+ public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
+ int viewType) {
+ // create a new view
+ View v = new TextView(parent.getContext());
+ // set the view's size, margins, paddings and layout parameters
+ ...
+ ViewHolder vh = new ViewHolder(v);
+ return vh;
+ }
+
+ // Replace the contents of a view (invoked by the layout manager)
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ // - get element from your dataset at this position
+ // - replace the contents of the view with that element
+ holder.mTextView.setText(mDataset[position]);
+
+ }
+
+ // Return the size of your dataset (invoked by the layout manager)
+ @Override
+ public int getItemCount() {
+ return mDataset.length;
+ }
+}
+</pre>
+
+
+<h2 id="cardview">CardView</h2>
+
+<p><code>CardView</code> extends the <code>FrameLayout</code> class and lets you show information
+inside a card with optional rounded corners:</p>
+
+<ul>
+ <li>To set the corner radius in your layouts, use the <code>android:cardCornerRadius</code>
+ attribute.</li>
+ <li>To set the corner radius in your code, use the <code>CardView.setRadius</code> method.</li>
+</ul>
+
+<p>To set the background color of a card, use the <code>android:cardBackgroundColor</code>
+attribute.</p>
+
+<p>To include a <code>CardView</code> in your layout:</p>
+
+<pre>
+<!-- A CardView that contains a TextView -->
+<android.support.v7.widget.CardView
+ android:id="@+id/card_view"
+ android:layout_gravity="center"
+ android:layout_width="200dp"
+ android:layout_height="200dp"
+ card_view:cardCornerRadius="4dp">
+
+ <TextView
+ android:id="@+id/info_text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+</android.support.v7.widget.CardView>
+</pre>
\ No newline at end of file
diff --git a/docs/html/preview/material/videos/ContactsAnim.mp4 b/docs/html/preview/material/videos/ContactsAnim.mp4
new file mode 100644
index 0000000..073f9dc
--- /dev/null
+++ b/docs/html/preview/material/videos/ContactsAnim.mp4
Binary files differ
diff --git a/docs/html/preview/material/videos/ContactsAnim.ogv b/docs/html/preview/material/videos/ContactsAnim.ogv
new file mode 100644
index 0000000..c5e751b
--- /dev/null
+++ b/docs/html/preview/material/videos/ContactsAnim.ogv
Binary files differ
diff --git a/docs/html/preview/material/videos/ContactsAnim.webm b/docs/html/preview/material/videos/ContactsAnim.webm
new file mode 100644
index 0000000..2a15ff5
--- /dev/null
+++ b/docs/html/preview/material/videos/ContactsAnim.webm
Binary files differ
diff --git a/docs/html/preview/material/views-shadows.jd b/docs/html/preview/material/views-shadows.jd
new file mode 100644
index 0000000..c5884d6
--- /dev/null
+++ b/docs/html/preview/material/views-shadows.jd
@@ -0,0 +1,86 @@
+page.title=Views and Shadows
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+ <li><a href="#elevation">View Elevation</a></li>
+ <li><a href="#shadows">Shadows and Outlines</a></li>
+ <li><a href="#clip">Clipping Views</a></li>
+</ol>
+</div>
+</div>
+
+<p>In apps with material design, depth has meaning. You should assign higher elevation values to more
+important UI elements in your app. The elevation value of a view determines the size of its
+shadow: views with higher Z values cast bigger shadows. Views only cast shadows on the Z=0 plane
+under an orthographic projection (the views do not scale for different values of Z).</p>
+
+
+<h2 id="elevation">View Elevation</h2>
+
+<p>The Z value for a view has two components, elevation and translation. The elevation is the
+static component, and the translation is used for animations:</p>
+
+<p><code>Z = elevation + translationZ</code></p>
+
+<p>To set the elevation of a view:</p>
+
+<ul>
+ <li>In a layout definition, use the <code>android:elevation</code> attribute.</li>
+ <li>In the code of an activity, use the <code>View.setElevation</code> method.</li>
+</ul>
+
+<p>To set the translation of a view, use the <code>View.setTranslationZ</code> method.</p>
+
+<p>The Z values are measured in the same units as the X and Y values (like <code>dp</code> or
+<code>px</code>).</p>
+
+
+<h2 id="shadows">Shadows and Outlines</h2>
+
+<p>The bounds of a view's background drawable determine the default shape of its shadow. To define
+a custom shape for a shadow, such as an oval, use the <code>View.setOutline</code> method:</p>
+
+<pre>
+View v = findViewById(R.id.my_view);
+
+// add 10px to the static elevation
+v.setTranslationZ(10);
+
+// set an oval shadow
+Outline outline = new Outline();
+outline.setOval(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+myView.setOutline(outline);
+</pre>
+
+<p>An <code>Outline</code> represents the outer shape of a graphics object. You can create
+<code>Outline</code> objects as in this example, or you can obtain the outline from a
+<code>Drawable</code> object with the <code>getOutline</code> method.</p>
+
+<p>The outline of a view also defines the ripple area for touch feedback.</p>
+
+<p>To prevent a view from casting a shadow, set its outline to <code>null</code>.</p>
+
+
+<h2 id="clip">Clipping Views</h2>
+
+<p>The Android L Developer Preview lets you clip a view to its outline area using the
+<code>View.setClipToOutline</code> method. Only rectangle, circle, and round rectangle outlines
+support clipping, as determined by the <code>Outline.canClip</code> method.</p>
+
+<p>To determine if a view has been clipped, use the <code>View.getClipToOutline</code> method.</p>
+
+<pre>
+// clip a view to an oval
+View v = findViewById(R.id.my_view);
+outline.setOval(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+myView.setOutline(outline);
+
+// if the view is not already clipped
+if (v.getClipToOutline() == false) {
+ v.setClipToOutline(true);
+}
+</pre>
\ No newline at end of file
diff --git a/docs/html/preview/preview_toc.cs b/docs/html/preview/preview_toc.cs
new file mode 100644
index 0000000..5920ecc
--- /dev/null
+++ b/docs/html/preview/preview_toc.cs
@@ -0,0 +1,87 @@
+<ul id="nav">
+
+
+ <li class="nav-section">
+ <div class="nav-section-header empty"><a href="<?cs var:toroot ?>preview/setup-sdk.html">Set up the Preview SDK
+ </a></div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section-header empty"><a href="<?cs var:toroot ?>preview/setup-devices.html">Set Up Hardware and AVDs
+ </a></div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section-header empty"><a href="<?cs var:toroot ?>preview/api-overview.html">API Overview
+ </a></div>
+ </li>
+ <li class="nav-section">
+
+ <div class="nav-section-header"><a href="<?cs var:toroot ?>preview/material/index.html">Material Design
+ </a></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>preview/material/get-started.html">Get Started</a></li>
+ <li><a href="<?cs var:toroot ?>preview/material/theme.html">Material Theme</a></li>
+ <li><a href="<?cs var:toroot ?>preview/material/ui-widgets.html">UI Widgets</a></li>
+ <li><a href="<?cs var:toroot ?>preview/material/views-shadows.html">Views and Shadows</a></li>
+ <li><a href="<?cs var:toroot ?>preview/material/animations.html">Animations</a></li>
+ <li><a href="<?cs var:toroot ?>preview/material/compatibility.html">Compatibility</a></li>
+ </ul>
+ </li>
+
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>preview/tv/index.html">TV</a>
+ </div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>preview/tv/start/index.html">
+ Get Started</a></li>
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>preview/tv/ui/index.html">
+ User Interface</a></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>preview/tv/ui/layouts.html">
+ Layouts</a></li>
+ <li><a href="<?cs var:toroot ?>preview/tv/ui/navigation.html">
+ Navigation</a></li>
+ <li><a href="<?cs var:toroot ?>preview/tv/ui/browse.html">
+ BrowseFragment</a></li>
+ <li><a href="<?cs var:toroot ?>preview/tv/ui/details.html">
+ DetailsFragment</a></li>
+ <li><a href="<?cs var:toroot ?>preview/tv/ui/in-app-search.html">
+ In-App Search</a></li>
+ <li><a href="<?cs var:toroot ?>preview/tv/ui/recommendations.html">
+ Recommendations</a></li>
+ </ul>
+ </li>
+ <li><a href="<?cs var:toroot ?>preview/tv/games/index.html">
+ Games on TV</a></li>
+ <li><a href="<?cs var:toroot ?>preview/tv/start/hardware-features.html">
+ Hardware Features</a></li>
+ <li><a href="<?cs var:toroot ?>preview/tv/adt-1/index.html">
+ ADT-1</a></li>
+ </ul>
+ </li>
+
+ <li class="nav-section">
+ <div class="nav-section-header empty">
+ <a href="<?cs var:toroot ?>preview/samples.html">Samples</a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section-header empty">
+
+ <a href="<?cs var:toroot ?>preview/l-developer-preview-reference.zip">Reference</a>
+
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section-header empty">
+ <a href="<?cs var:toroot ?>preview/support.html">Support</a>
+ </div>
+ </li>
+ <li class="nav-section">
+ <div class="nav-section-header empty">
+ <a href="<?cs var:toroot ?>preview/tos.html">Terms of Service</a>
+ </div>
+ </li>
+</ul>
diff --git a/docs/html/preview/samples.jd b/docs/html/preview/samples.jd
new file mode 100644
index 0000000..67404b6
--- /dev/null
+++ b/docs/html/preview/samples.jd
@@ -0,0 +1,16 @@
+page.title=Samples
+
+@jd:body
+
+<p>The code samples for the L Developer Preview are available in the Android SDK Manager under the
+L Preview section. Here is a summary of everything that is available:</p>
+
+<ul>
+ <li></li>
+ <li></li>
+ <li></li>
+ <li></li>
+ <li></li>
+ <li></li>
+ <li></li>
+ </ul>
diff --git a/docs/html/preview/setup-devices.jd b/docs/html/preview/setup-devices.jd
new file mode 100644
index 0000000..86e4845
--- /dev/null
+++ b/docs/html/preview/setup-devices.jd
@@ -0,0 +1,90 @@
+page.title=Setting Up Hardware and AVDs
+@jd:body
+
+<p>The Android L developer preview provides you with 32-bit system images
+to flash the following devices:
+</p>
+
+<ul>
+ <li>Nexus 5</li>
+ <li>Nexus 7 Wi-Fi (version 2, released in 2013)</li>
+</ul>
+
+<p>In addition, you also get the emulator system images, which includes
+experimental 64-bit system images along with standard 32-bit system images.
+</p>
+
+<h2>Installing the L Preview System Image</h2>
+
+<!-- Will we get an official warning text from the lawyercats? Is this it? -->
+<p class="warning"><b>Warning</b>: This is a preview version of the Android
+system image, and is subject to change. Your use of this system image is
+governed by the Android SDK Preview License Agreement. The Android preview
+system image is not a stable release, and may contain errors and defects that
+can result in damage to your computer systems, devices, and data. The preview
+Android system image is not subject to the same testing as the factory OS and
+can cause your phone and installed services and applications to stop working.
+</p>
+
+
+<ol>
+ <li>Download and extract the Android Developer Preview package to a directory
+ (which we'll call <code><l_download_dir></code> in these
+ instructions).</li>
+ <li>Connect your powered-off Android device to your development machine. Put
+ the device in fastboot mode by pressing and holding the following buttons:
+ <ul>
+ <li><strong>Nexus 5:</strong> <i>volume down</i> + <i>volume up</i> +
+ <i>power</i></li>
+ <li><strong>Nexus 7:</strong> <i>volume down</i> + <i>power</i> </li>
+ </ul>
+ <p class="note">Alternatively, you can enter fastboot mode by booting up
+ the device and running <code>adb reboot bootloader</code> with USB debugging
+ turned on.</p>
+ </li>
+ <li>Follow the instructions at
+ <a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>
+ to set up your system for flashing devices.</li>
+ <li>Run the <code><l_download_dir>/flash-all</code> script
+ corresponding to your platform. This script flashes all of the system data
+ onto the phone.</li> <!-- Confirm names of flash scripts -->
+ <li>(Optional) After flashing is complete, lock your device's bootloader by
+ putting it in fastboot mode and running <code>fastboot oem lock</code>.
+ (This does not wipe your device.) Once you do this, you will not be able to
+ flash your device until you run run <code>fastboot oem unlock</code>,
+ which unlocks the bootloader and wipes your device. We recommend you leave the
+ bootloader unlocked until you are done with flashing the device.</li>
+</ol>
+
+<h3>Reverting a Device to Factory Specifications</h3>
+
+ <p>If you want to uninstall the L Preview and revert the device to factory
+specifications, go to <a href="http://developers.google.com/android
+/nexus/images">developers.google.com/android</a> and download the image you want
+to flash to for your device. Follow the instructions on that page to flash the
+image to your device.</p>
+
+
+<h2>Setting up an AVD</h2>
+
+<p>You can set up <a href="{@docRoot}tools/devices/">Android Virtual Devices
+(AVD)</a> and use the emulator to build and test apps with the L Preview.</p>
+
+<p>To create an AVD with the AVD Manager:</p>
+
+<ol>
+ <li>Install the L Preview SDK in your development environment, as described
+ in <a href="{@docRoot}preview/setup-sdk.html">Setting Up the Preview
+ SDK.</a></li>
+ <li>Follow the steps in
+ <a href="{@docRoot}tools/devices/managing-avds.html">Managing AVDs with AVD
+ Manager</a>. Use the following settings:
+ <ul>
+ <li><b>Device:</b> Either Nexus 5 or Nexus 7</li>
+ <li><b>Target:</b> <!-- Confirm exact text when we have final distro -->
+ Android L (Preview) - API Level L</li>
+ </ul>
+ <!-- Confirm this works when you can download image through SDK manager! -->
+ </li>
+</ol>
+
diff --git a/docs/html/preview/setup-sdk.jd b/docs/html/preview/setup-sdk.jd
new file mode 100644
index 0000000..32a33b6
--- /dev/null
+++ b/docs/html/preview/setup-sdk.jd
@@ -0,0 +1,36 @@
+page.title=Setting Up the Preview SDK
+@jd:body
+
+<p>The Preview SDK is available from the Android SDK Manager. <!-- Not yet! -->
+This document assumes that you are familiar with Android app development, such
+as using the Android SDK Manager and creating projects. If you're new to
+Android, see <a href="/training/basics/firstapp/index.html">Building Your First
+App</a> training lesson first.</a></p>
+
+<h2>Download the SDK</h2>
+
+<ol>
+ <li>Start the Android SDK Manager.</li>
+ <li>In the <b>Tools</b> section, select the latest Android <b>SDK Tools</b>,
+ <b>Platform-tools</b>, and <b>Build-tools</b>.</li>
+ <!-- Android L not yet showing up in Android SDK Manager... -->
+ <li>Select everything under the <b>Android L Developer Preview</b> section and
+ click <b>Install packages...</b></li>
+ <li>Accept the Licensing Agreement for all of the packages and click
+ <b>Install</b>.</li>
+</ol>
+
+<h2>Set up your environment</h2>
+
+<ol>
+ <li>Create a new Android project with the following properties:
+ <ul>
+ <li>Minimum SDK Version: L</li>
+ <li>Target SDK Version: L</li>
+ <li>Build Target: L</li>
+ </ul>
+ </li>
+ <li>Choose the theme <code>Theme.Material</code>
+ <!-- put in name as it appears in Eclipse menu? -->
+
+</ol>
diff --git a/docs/html/preview/support.jd b/docs/html/preview/support.jd
new file mode 100644
index 0000000..23ce6ff
--- /dev/null
+++ b/docs/html/preview/support.jd
@@ -0,0 +1,22 @@
+page.title=Support
+
+@jd:body
+
+<p>If you've encountered bugs or have feedback about the L Developer Preview, create
+an issue on our bug tracker</p>
+
+<p>Go to the Bug Tracker</p>
+
+<h2>Release Notes</h2>
+
+<p>June 25, 2014 - Initial Release of the L Developer Preview</p>
+
+<ul>
+ <li></li>
+ <li></li>
+ <li></li>
+ <li></li>
+ <li></li>
+ <li></li>
+ <li></li>
+ </ul>
diff --git a/docs/html/preview/tos.jd b/docs/html/preview/tos.jd
new file mode 100644
index 0000000..602439f
--- /dev/null
+++ b/docs/html/preview/tos.jd
@@ -0,0 +1,9 @@
+page.title=License Agreement
+
+@jd:body
+
+<p><!-- Will this link change before we publish (to a clean version of the doc)?
+ Or will we scrub the doc's comments & revision history? -->
+<a href="https://docs.google.com/a/google.com/document/d/1OixnM1Q890ExOzDB3Z-FDD6Sb2kF4uZQiMxsYVII8F0/edit?usp=sharing">L
+Preview Terms of Service</a>
+</p>
\ No newline at end of file
diff --git a/docs/html/sdk/exploring.jd b/docs/html/sdk/exploring.jd
index 7749060..b34c1cf 100644
--- a/docs/html/sdk/exploring.jd
+++ b/docs/html/sdk/exploring.jd
@@ -5,163 +5,6 @@
@jd:body
-<p>The Android SDK is composed of modular packages that you can download separately using
-the Android SDK Manager. For example, when the SDK Tools are updated or a new version of
-the Android platform is released, you can use the SDK Manager to quickly download them to
-your environment. Simply follow the procedures described in <a
-href="{@docRoot}sdk/installing/adding-packages.html">Adding Platforms and Packages</a>.</p>
-
-<p>There are several different packages available for the Android SDK. The table below describes
-most of the available packages and where they're located once you download them.</p>
-
-
-<h2 id="Packages">Available Packages</h2>
-
-
-<table>
- <tr><th>Package</th><th>Description</th><th>File Location</th></tr>
- <tr>
- <td><a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools</a></td>
- <td>Contains tools for debugging and testing, plus other
-utilities that are required to develop an app. If you've just installed the SDK starter package,
-then you already have the latest version of this package. Make sure you keep this up to date.</td>
- <td>{@code <sdk>/tools/}</td></tr>
- <tr><td>SDK Platform-tools</td>
- <td>Contains platform-dependent tools for developing and debugging
-your application. These tools support the latest features of the Android platform and are typically
-updated only when a new platform becomes available. These tools are always backward compatible with
-older platforms, but you must be sure that you have the latest version of these tools when you
-install a new SDK platform.</td>
- <td>{@code <sdk>/platform-tools/}</td>
- </tr>
-
- <tr>
- <td>Documentation</td>
- <td>An offline copy of the latest documentation for the Android
-platform APIs.</td>
- <td>{@code <sdk>/docs/}</td>
- </tr>
- <tr><td>SDK Platform</td>
- <td>There's one SDK Platform available for each version of Android. It includes an {@code
-android.jar} file with a fully compliant Android library. In order to build an Android app, you must
-specify an SDK platform as your build target.</td>
- <td>{@code <sdk>/platforms/<android-version>/}</td>
- </tr>
- <tr>
- <td>System Images</td>
- <td>Each platform version offers one or more different system images (such as for ARM
-and x86). The Android emulator requires a system image to operate. You should always test your
-app on the latest version of Android and using the emulator with the latest system image is a
-good way to do so.</td>
- <td>{@code <sdk>/platforms/<android-version>/}</td>
- </tr>
- <tr>
- <td>Sources for Android SDK</td>
- <td>A copy of the Android platform source code that's useful for
-stepping through the code while debugging your app.</td>
- <td>{@code <sdk>/sources/}</td>
- </tr>
- <tr>
- <td><a href="{@docRoot}tools/samples/index.html">Samples for SDK</a></td>
- <td>A collection of sample apps that demonstrate a variety of the
-platform APIs. These are a great resource to browse Android app code. The API Demos app in
-particular provides a huge number of small demos you should explore.</td>
- <td>{@code <sdk>/platforms/<android-version>/samples/}</td>
- </tr>
- <tr>
- <td><a href="http://developers.google.com/android">Google APIs</a></td>
- <td>An SDK add-on that provides both a platform you can use to develop an app
-using special Google APIs and a system image for the emulator so you can test your app using the
-Google APIs.</td>
- <td>{@code <sdk>/add-ons/}</td>
- </tr>
-
- <tr>
- <td><a href="{@docRoot}tools/support-library/index.html">Android Support</a></td>
- <td>A static library you can include in your app sources in order to use powerful
-APIs that aren't available in the standard platform. For example, the support library
-contains versions of the {@link android.support.v4.app.Fragment} class that's compatible with
-Android 1.6 and higher (the class was originally introduced in Android 3.0) and the {@link
-android.support.v4.view.ViewPager} APIs that allow you to easily build a side-swipeable UI.</td>
- <td>{@code <sdk>/extras/android/support/}</td>
- </tr>
- <tr>
- <td><a href="{@docRoot}google/play/billing/index.html">Google Play Billing</a></td>
- <td>Provides the static libraries and samples that allow you to
-integrate billing services in your app with Google Play.</td>
- <td>{@code <sdk>/extras/google/}</td>
- </tr>
- <tr>
- <td><a href="{@docRoot}google/play/licensing/index.html">Google Play Licensing</a></td>
- <td>Provides the static libraries and samples that allow you to perform license verification for
-your app when distributing with Google Play.</td>
- <td>{@code <sdk>/extras/google/}</td>
- </tr>
-</table>
-
-<p>The above table is not comprehensive and you can <a
-href="#AddingSites">add new sites</a> to download additional packages from third-parties.</p>
-
-<p>In some cases, an SDK package may require a specific minimum revision of
-another package or SDK tool. For example, there may be a dependency between the ADT Plugin for
-Eclipse and
-the SDK Tools package. When you install the SDK Tools
-package, you should also upgrade to the required version of ADT (if you
-are developing in Eclipse). In this case, the major version number for your ADT plugin should
-always match the revision number of your SDK Tools (for example, ADT 8.x requires SDK Tools r8).
-</p>
-
-<p>The development tools will notify you with debug warnings if there is dependency that you need to
-address. The Android SDK Manager also enforces dependencies by requiring that you download any
-packages that are needed by those you have selected.</p>
-
-
-
-
-
-<h2 id="AddingSites">Adding New Sites</h2>
-
-<p>By default, <strong>Available Packages</strong> displays packages available from the
-<em>Android Repository</em> and <em>Third party Add-ons</em>. You can add other sites that host
-their own Android SDK add-ons, then download the SDK add-ons
-from those sites.</p>
-
-<p>For example, a mobile carrier or device manufacturer might offer additional
-API libraries that are supported by their own Android-powered devices. In order
-to develop using their libraries, you must install their Android SDK add-on, if it's not already
-available under <em>Third party Add-ons</em>. </p>
-
-<p>If a carrier or device manufacturer has hosted an SDK add-on repository file
-on their web site, follow these steps to add their site to the Android SDK
-Manager:</p>
-
-<ol>
- <li>Select <strong>Available Packages</strong> in the left panel.</li>
- <li>Click <strong>Add Add-on Site</strong> and enter the URL of the
-<code>repository.xml</code> file. Click <strong>OK</strong>.</li>
-</ol>
-<p>Any SDK packages available from the site will now be listed under a new item named
-<strong>User Add-ons</strong>.</p>
-
-
-
-
-<h2 id="troubleshooting">Troubleshooting</h2>
-
-<p><strong>Problems connecting to the SDK repository</strong></p>
-
-<p>If you are using the Android SDK Manager to download packages and are encountering
-connection problems, try connecting over http, rather than https. To switch the
-protocol used by the Android SDK Manager, follow these steps: </p>
-
-<ol>
- <li>With the Android SDK Manager window open, select "Settings" in the
- left pane. </li>
- <li>On the right, in the "Misc" section, check the checkbox labeled "Force
- https://... sources to be fetched using http://..." </li>
- <li>Click <strong>Save & Apply</strong>.</li>
-</ol>
-
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index e7f78e8..dc3b9dd 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -206,12 +206,10 @@
<div id="next-steps" style="display:none;position:absolute;width:inherit">
- <p>Now that you've downloaded the Android SDK, you don't need to return here
- for SDK updates. The SDK tools allow you to
- install additional packages and future updates from the SDK Manager.</p>
- <p>For instructions about setting up your Android SDK for the first time,
- read <a id="next-link" href="{@docRoot}sdk/installing/bundle.html">Setting
- Up the ADT Bundle</a>.</p>
+ <p>You're just a few steps away from building apps for Android!</p>
+ <p>In a moment, you'll be redirected to <a
+ id="next-link" href="{@docRoot}sdk/installing/index.html">Installing the
+ Android SDK</a>.</p>
</div><!-- end next-steps -->
@@ -232,7 +230,6 @@
</div>
-
</div><!-- end TOS -->
@@ -255,16 +252,30 @@
<b>ADT (Android Developer Tools)</b> to
streamline your Android app development.</p>
-<p>With a single download, the ADT Bundle
+
+<!-- this appears when viewing the online docs -->
+<div class="online" style="margin-bottom:85px">
+
+<a class="big button subtitle" id="download-bundle-button"
+href="" style="width:295px;display:block;margin:25px 0" ></a>
+
+<p id="not-supported">Choose the SDK package for your OS from the table below.</p>
+
+
+ <p>With a single download, the Eclipse ADT bundle
includes everything you need to begin developing apps:</p>
<ul>
<li>Eclipse + ADT plugin</li>
<li>Android SDK Tools</li>
<li>Android Platform-tools</li>
-<li>The latest Android platform</li>
-<li>The latest Android system image for the emulator</li>
+<li>A version of the Android platform</li>
+<li>A version of the Android system image for the emulator</li>
</ul>
+</div>
+<!-- end online -->
+
+
<!-- this appears when viewing the offline docs -->
<p class="offline">
@@ -277,52 +288,44 @@
<div class="col-7" style="margin-right:0;">
- <img src="{@docRoot}images/sdk-cube.png" alt="" height=264 />
+ <img src="{@docRoot}images/tools-home.png" alt="" height="347" width="400" />
-<!-- this appears when viewing the online docs -->
-<div class="online">
-
-<a class="big button subtitle" id="download-bundle-button"
-href="" style="display:none;width:265px;margin:0 auto;display:block" ></a>
-
-
-
-
-<p id="not-supported">Choose the SDK package for your OS from the table below.</p>
-
-</div>
-<!-- end online -->
</div><!-- end col-7 -->
+<div class="col-7" style="background: #ddd;
+ padding: 30px 20px; width:350px; margin:20px 0 0 20px;">
+
+ <h3 style="margin-top:0">
+ <a href="/sdk/installing/studio.html">Get Android Studio Beta</a>
+ </h3>
+
+ <p>
+ Android Studio is a new IDE powered by IntelliJ that provides new features and improvements
+ over ADT. It's currently in beta but will be the official Android IDE once it's ready.</p>
+ <p style="margin: 0;">
+ <a href="/sdk/installing/studio.html">Learn more about Android Studio</a></p>
+ </div>
+
+
<!-- alternative SDK options -->
-<div class="col-13" style="margin:0;">
+<div class="col-13" style="margin:-70px 0 0;">
-<!-- this appears only when viewing the online docs -->
-<div class="online caution">
-<h3 style="margin:0 0 10px 0;font-size:14px">Android Studio Early Access Preview</h3>
+<p style="width:340px">If you prefer to use an existing version of Eclipse or another IDE,
+you can instead download the stand-alone Android SDK Tools:</p>
-<p>A new Android development environment called Android Studio,
-based on IntelliJ IDEA, is now available as an <strong>early access preview</strong>.
-For more information, see
-<a href="{@docRoot}sdk/installing/studio.html">Getting Started with Android Studio</a>.</p>
-</div>
-
-<p>If you prefer to use an existing version of Eclipse or another IDE,
-you can instead take a more customized approach to installing
-the Android SDK. See the following instructions:</p>
<h4 id="ExistingIDE"><a href='' class="expandable"
onclick="toggleExpandable(this,'.myide');hideExpandable('.pax,.reqs');return false;"
- >USE AN EXISTING IDE</a></h4>
+ >GET THE SDK FOR AN EXISTING IDE</a></h4>
<div class="col-13 myide" style="margin:0 0 15px;display:none;">
@@ -335,13 +338,11 @@
<a class="button subtitle" id="download-tools-button" href="" style="display:none" ></a>
</p>
-
</div>
-
<h4 id="Requirements"><a href='' class="expandable"
onclick="toggleExpandable(this,'.reqs');hideExpandable('.pax,.myide');return false;"
>SYSTEM REQUIREMENTS</a></h4>
@@ -361,23 +362,9 @@
</ul>
</div>
-<div class="col-6 reqs" style="margin:0 0 15px 20px;display:none;">
-<h5>Eclipse IDE</h5>
- <ul>
- <li><a href="http://eclipse.org/mobile/">Eclipse</a> 3.7.2 (Indigo) or greater
-<p class="note"><strong>Note:</strong> Eclipse 3.6 (Helios) is no longer
-supported with the latest version of ADT.</p></li>
- <li>Eclipse <a href="http://www.eclipse.org/jdt">JDT</a> plugin (included
-in most Eclipse IDE packages) </li>
- <li><a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">JDK 6</a>
- (JRE alone is not sufficient)</li>
- <li><a href="{@docRoot}tools/sdk/eclipse-adt.html">Android Development Tools plugin</a>
-(recommended)</li>
- <li><strong>Not</strong> compatible with GNU Compiler for Java (gcj)</li>
- </ul>
+<div class="col-7 reqs" style="margin:0 0 80px 20px;display:none;">
-
-<h5>Other development environments</h5>
+<h5>Development tools</h5>
<ul>
<li><a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">JDK 6</a>
(JRE alone is not sufficient)</li>
@@ -387,6 +374,4 @@
<p class="note"><strong>Note:</strong> Some Linux distributions may include JDK 1.4 or Gnu Compiler
for Java, both of which are <em>not</em> supported for Android development. </p>
-</div><!-- end col-7 reqs -->
-
-
+</div><!-- end reqs -->
diff --git a/docs/html/sdk/installing/adding-packages.jd b/docs/html/sdk/installing/adding-packages.jd
index bba936e..e6c0118 100644
--- a/docs/html/sdk/installing/adding-packages.jd
+++ b/docs/html/sdk/installing/adding-packages.jd
@@ -1,63 +1,226 @@
-page.title=Adding Platforms and Packages
+page.title=Adding SDK Packages
@jd:body
+<style>
+ol.large {
+ margin-left:0;
+}
+ol.large > li {
+ list-style-position: inside;
+ list-style-type:none;
+ margin:30px 0 0 0;
+ padding:30px 20px;
+ background:#eee;
+}
+ol.large > li:nth-child(odd) {
+}
+ol.large > li:before {
+ display:inline;
+ left:-40px;
+ float:left;
+ width:20px;
+ font-size:20px;
+ line-height:20px;
+}
+ol.large > li > h2 {
+ font-size:20px;
+ line-height:20px;
+ padding:0 0 0 20px;
+ margin:0 0 20px 0;
+ display:inline-block;
+ font-weight:normal;
+}
+ol.large > li:nth-child(1):before {
+ content:"1. ";
+}
+ol.large > li:nth-child(2):before {
+ content:"2. ";
+}
+ol.large > li:nth-child(3):before {
+ content:"3. ";
+}
+ol.large > li:nth-child(4):before {
+ content:"4. ";
+}
+ol.large > li:nth-child(5):before {
+ content:"5. ";
+}
+ol.large > li:nth-child(6):before {
+ content:"6. ";
+}
+</style>
-<p>The Android SDK separates tools, platforms, and other components into packages you can
- download using the Android SDK Manager. The original
-SDK package you've downloaded includes only the SDK Tools. To develop an Android app,
-you also need to download at least one Android platform and the latest SDK Platform-tools.</p>
-<ol>
-<li>Launch the SDK Manager.
-<p>If you've used the Windows installer to install the SDK tools, you should already have the
-Android SDK Manager open. Otherwise, you can launch the Android SDK Manager in one of the following
-ways:</p>
+<p>
+By default, the Android SDK does not include everything you need to start developing.
+The SDK separates tools, platforms, and other components into packages you can
+download as needed using the
+<a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>.
+So before you can start, there are a few packages you should add to your Android SDK.</p>
+
+<p>To start adding packages, launch the Android SDK Manager in one of the following ways:</p>
<ul>
- <li>On Windows, double-click the <code>SDK Manager.exe</code> file at the root of the Android
-SDK directory.</li>
- <li>On Mac or Linux, open a terminal and navigate to the <code>tools/</code> directory in the
-Android SDK, then execute <code>android sdk</code>.</li>
+ <li>In Eclipse or Android Studio, click <strong>SDK Manager</strong>
+<img src="{@docRoot}images/tools/sdk-manager-studio.png"
+style="vertical-align:bottom;margin:0;height:17px" /> in the toolbar.</li>
+ <li>If you're not using Eclipse or Android Studio:
+ <ul>
+ <li>Windows: Double-click the <code>SDK Manager.exe</code> file at the root of the Android
+ SDK directory.</li>
+ <li>Mac/Linux: Open a terminal and navigate to the <code>tools/</code> directory in the
+ Android SDK, then execute <code>android sdk</code>.</li>
+ </ul>
+ </li>
</ul>
+
+<p>When you open the SDK Manager for the first time, several packages will be selected by
+default. Leave these selected, but be sure you have everything you need
+to get started by following these steps:</p>
+
+
+<ol class="large">
+<li>
+ <h2 id="GetTools" class="norule">Get the latest SDK tools</h2>
+
+<img src="/images/sdk_manager_packages.png" alt="" width="350" style="float:right;margin-left:20px" />
+
+ <p>As a minimum when setting up the Android SDK,
+ you should download the latest tools and Android platform:</p>
+ <ol>
+ <li>Open the Tools directory and select:
+ <ul>
+ <li><strong>Android SDK Tools</strong></li>
+ <li><strong>Android SDK Platform-tools</strong></li>
+ <li><strong>Android SDK Build-tools</strong> (highest version)</li>
+ </ul>
+ </li>
+ <li>Open the first Android X.X folder (the latest version) and select:
+ <ul>
+ <li><strong>SDK Platform</strong></li>
+ <li>A system image for the emulator, such as <br>
+ <strong>ARM EABI v7a System Image</strong></li>
+ </ul>
+ </li>
+ </ol>
</li>
-<li>The SDK Manager shows all the SDK packages available for you to add to your Android SDK.
-As a minimum configuration for your SDK, we recommend you install the following:
-<ul>
- <li>The latest Tools packages (check the <strong>Tools</strong> folder).</li>
- <li>The latest version of Android (check the first <strong>Android</strong> folder).</li>
- <li>The Android Support Library (open the <strong>Extras</strong> folder and check
- <strong>Android Support Library</strong>).</li>
-</ul>
+<li>
+ <h2 id="GetSupportLib" class="norule">Get the support library for additional APIs</h2>
-<p>Once you've chosen your packages, click <strong>Install</strong>. The Android SDK Manager
-installs the selected packages into your Android SDK environment.</li>
+ <div class="sidebox">
+ <p>The support library is required for:</p>
+ <ul>
+ <li><a href="{@docRoot}wear/index.html">Android Wear</a></li>
+ <li><a href="{@docRoot}tv/index.html">Android TV</a></li>
+ <li><a href="{@docRoot}google/play-services/cast.html">Google Cast</a></li>
+ </ul>
+
+ <p>It also provides these popular APIs:</p>
+ <ul>
+ <li><a href="{@docRoot}reference/android/support/v4/widget/DrawerLayout.html">Navigation
+ drawer</a></li>
+ <li><a href="{@docRoot}reference/android/support/v4/view/ViewPager.html">Swipe views</a></li>
+ <li><a href="{@docRoot}reference/android/support/v7/app/ActionBar.html">Backward-compatible
+ action bar</a></li>
+ </ul>
+ </div>
+
+ <p>The <a href="{@docRoot}tools/support-library/features.html">Android Support Library</a>
+ provides an extended set of APIs that are compatible with most versions of Android.</p>
+
+ <p>Open the <strong>Extras</strong> directory and select:</p>
+ <ul>
+ <li><strong>Android Support Repository</strong></li>
+ <li><strong>Android Support Library</strong></li>
+ </ul>
+
+ <p> </p>
+ <p> </p>
+
+</li>
+
+
+<li>
+ <h2 id="GetGoogle" class="norule">Get Google Play services for even more APIs</h2>
+
+ <div class="sidebox">
+
+ <p>The Google Play services APIs provide a variety of features and services for your Android
+ apps, such as:</p>
+ <ul>
+ <li><a href="{@docRoot}google/play-services/plus.html">User authentication</a></li>
+ <li><a href="{@docRoot}google/play-services/maps.html">Google Maps</a></li>
+ <li><a href="{@docRoot}google/play-services/cast.html">Google Cast</a></li>
+ <li><a href="{@docRoot}google/play-services/games.html">Games achievements and
+ leaderboards</a></li>
+ <li><a href="{@docRoot}google/play-services/index.html">And much more</a></li>
+ </ul>
+ </div>
+
+ <p>To develop with Google APIs, you need the Google Play services package:</p>
+ <p>Open the <strong>Extras</strong> directory and select:</p>
+ <ul>
+ <li><strong>Google Repository</strong></li>
+ <li><strong>Google Play services</strong></li>
+ </ul>
+
+ <p class="note"><strong>Note:</strong> Google Play services APIs are not available on all
+ Android-powered devices, but are available on all devices with Google Play Store. To use these
+ APIs in the Android emulator, you must also install the the <strong>Google APIs</strong>
+ system image from the latest Android X.X directory in the SDK Manager.</p>
+</li>
+
+
+<li>
+ <h2 id="Install" class="norule">Install the packages</h2>
+ <p>Once you've selected all the desired packages, continue to install:</p>
+ <ol>
+ <li>Click <strong>Install X packages</strong>.</li>
+ <li>In the next window, double-click each package name on the left
+ to accept the license agreement for each.</li>
+ <li>Click <strong>Install</strong>.</li>
+ </ol>
+ <p>The download progress is shown at the bottom of the SDK Manager window.
+ <strong>Do not exit the SDK Manager</strong> or it will cancel the download.</p>
+</li>
+
+<li>
+ <h2 id="Build" class="norule">Build something!</h2>
+
+<p>With the above packages now in your Android SDK, you're ready to build apps
+for Android. As new tools and other APIs become available, simply launch the SDK Manager
+ to download the new packages for your SDK.</p>
+
+<p>Here are a few options for how you should proceed:</p>
+
+<div class="cols" style="padding:10px 0">
+<div class="col-4">
+<h3>Get started</h3>
+<p>If you're new to Android development, learn the basics of Android apps by following
+the guide to <strong><a href="{@docRoot}training/basics/firstapp/index.html"
+>Building Your First App</a></strong>.</p>
+
+</div>
+<div class="col-4 box">
+<h3>Build for wearables</h3>
+<p>If you're ready to start building apps for Android wearables, see the guide to
+<strong><a href="{@docRoot}wear/preview/start.html">Building Apps for Android Wear</a></strong>.</p>
+
+</div>
+<div class="col-4 box">
+<h3>Use Google APIs</h3>
+<p>To start using Google APIs, such as Maps or
+Play Game services, see the guide to
+<strong><a href="{@docRoot}google/play-services/setup.html">Setting Up Google Play
+Services</a></strong>.</p>
+
+</div>
+</div><!-- end cols -->
+
+
+</li>
+
</ol>
-<p>With these packages installed, you're ready to start developing.
-To get started, read <a href="{@docRoot}training/basics/firstapp/index.html"
->Building Your First App</a>.</p>
-
-<img src="/images/sdk_manager_packages.png" alt="" height="396" />
-<p class="img-caption"><strong>Figure 1.</strong> The Android SDK Manager shows the
-SDK packages that are available, already installed, or for which an update is available.</p>
-
-
-
-<h3>Additional information</h3>
-
-<ul>
- <li>For more information about using the SDK Manager and some of the available packages,
-see the <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> document.</li>
- <li>This web site provides all information you need to develop Android apps, including <a
-href="{@docRoot}design/index.html">design guidelines</a>,
-<a href="{@docRoot}training/index.html">developer training</a>, <a
-href="{@docRoot}reference/packages.html">API reference</a>, and information
-about how you can <a href="{@docRoot}distribute/index.html">distribute your app</a>. We recommend
-you begin by reading <a href="{@docRoot}training/basics/firstapp/index.html"
->Building Your First App</a>.</li>
- <li>For additional resources about developing and distributing your app, see the
-<a href="{@docRoot}support.html">Developer Support Resources</a>.</li>
-</ul>
-
diff --git a/docs/html/sdk/installing/bundle.jd b/docs/html/sdk/installing/bundle.jd
index 1f7da55..22bdd11 100644
--- a/docs/html/sdk/installing/bundle.jd
+++ b/docs/html/sdk/installing/bundle.jd
@@ -1,45 +1,3 @@
page.title=Setting Up the ADT Bundle
@jd:body
-
-
-<p>The ADT Bundle provides everything you need to start developing apps, including
-a version of the Eclipse IDE with built-in <b>ADT (Android Developer Tools)</b> to
-streamline your Android app development.
-If you haven't already, go download the <a href="{@docRoot}sdk/index.html"
->Android ADT Bundle</a>. (If you downloaded the SDK Tools only, for use with an
-existing IDE, you should instead read
-<a href="{@docRoot}sdk/installing/index.html">Setting Up an Existing IDE</a>.)</p>
-
-<h3>Install the SDK and Eclipse IDE</h3>
-<ol>
-<li>Unpack the ZIP file
-(named {@code adt-bundle-<os_platform>.zip}) and save it to an appropriate location,
-such as a "Development" directory in your home directory.</li>
-<li>Open the {@code adt-bundle-<os_platform>/eclipse/} directory and launch
-<strong>eclipse</strong>.</li>
-</ol>
-
-<p>That's it! The IDE is already loaded with the Android Developer Tools plugin and
-the SDK is ready to go. To start developing, read <a href="{@docRoot}training/basics/firstapp/index.html"
->Building Your First App</a>.</p>
-
-<p class="caution"><strong>Caution:</strong> Do not move any of the files or directories
-from the {@code adt-bundle-<os_platform>} directory. If you move the {@code eclipse}
-or {@code sdk} directory, ADT will not be able to locate the SDK and you'll
-need to manually update the ADT preferences.</p>
-
-<h3>Additional information</h3>
-
-<p>As you continue developing apps, you may need to install additional versions
-of Android for the emulator and other packages such as the library for
-Google Play In-app Billing. To install more packages, use
-the <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</p>
-
-<p>Everything you need to develop Android apps is on this web site, including <a
-href="{@docRoot}design/index.html">design guidelines</a>,
-<a href="{@docRoot}training/index.html">developer training</a>, <a
-href="{@docRoot}reference/packages.html">API reference</a>, and information
-about how you can <a href="{@docRoot}distribute/index.html">distribute your app</a>.
-For additional resources about developing and distributing your app, see the
-<a href="{@docRoot}support.html">Developer Support Resources</a>.</p>
\ No newline at end of file
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index 6b63ba7..3671726 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -1,19 +1,213 @@
-page.title=Setting Up an Existing IDE
+page.title=Installing the Android SDK
@jd:body
-
-<p>You should have already downloaded the <a href="{@docRoot}sdk/index.html#ExistingIDE"
->Android SDK Tools</a>. (If you downloaded the ADT Bundle, you should instead read
-<a href="{@docRoot}sdk/installing/bundle.html">Setting Up the ADT Bundle</a>.)</p>
-
-<p>The SDK Tools package is not the complete SDK environment. It includes only the core SDK tools, which you can
-use to download the rest of the SDK packages (such as the latest system image).</p>
+<style>
+.paging-links {
+ margin:0 0 80px;
+}
+.paging-links .next-page-link {
+ right:initial;
+}
+.procedure-box {
+ padding:20px 20px 5px;
+ margin-bottom:1em;
+ background:#eee;
+}
+</style>
-<div id="win" class="docs" style="display:none">
-<h3>Getting started on Windows</h3>
+<!-- ################### ADT BUNDLE ####################### -->
+<div id="adt" heading="Installing the Eclipse ADT Bundle" style="display:none">
+
+
+<p>The Eclipse ADT Bundle provides everything you need to start developing apps, including
+the Android SDK tools and a version of the Eclipse IDE with built-in ADT
+(Android Developer Tools) to streamline your Android app development.</p>
+
+<p>If you didn't download the Eclipse ADT bundle, go <a href="{@docRoot}sdk/index.html"
+><b>download the Eclipse ADT bundle now</b></a>, or switch to the
+<a href="{@docRoot}sdk/installing/index.html?pkg=studio">Android Studio
+install</a> or <a href="{@docRoot}sdk/installing/index.html?pkg=tools">stand-alone SDK Tools
+install</a> instructions</i>.</p>
+
+<div class="procedure-box">
+<p><b>To set up the ADT Bundle:</b></p>
+<ol>
+<li>Unpack the ZIP file
+(named {@code adt-bundle-<os_platform>.zip}) and save it to an appropriate location,
+such as a "Development" directory in your home directory.</li>
+<li>Open the {@code adt-bundle-<os_platform>/eclipse/} directory and launch
+<strong>Eclipse</strong>.</li>
+</ol>
+
+<p class="caution"><strong>Caution:</strong> Do not move any of the files or directories
+from the {@code adt-bundle-<os_platform>} directory. If you move the {@code eclipse/}
+or {@code sdk/} directory, ADT will not be able to locate the SDK and you'll
+need to manually update the ADT preferences.</p>
+</div>
+
+<p>Eclipse with ADT is now ready and loaded with the Android developer tools, but there are still
+a couple packages you should add to make your Android SDK complete.</p>
+
+<p class="paging-links">
+<a href="{@docRoot}sdk/installing/adding-packages.html" class="next-page-link">
+Continue: Adding SDK Packages</a></p>
+
+
+</div>
+<!-- ################ END ADT BUNDLE ##################### -->
+
+
+
+
+
+
+<!-- ################ STUDIO ##################### -->
+<div id="studio" heading="Installing Android Studio" style="display:none">
+
+<p>Android Studio provides everything you need to start developing apps, including
+the Android SDK tools and the Android Studio IDE (powered by IntelliJ) to
+streamline your Android app development.</p>
+
+<p>If you didn't download Android Studio, go <a href="{@docRoot}sdk/installing/studio.html"
+><b>download Android Studio now</b></a>, or switch to the
+<a href="{@docRoot}sdk/installing/index.html?pkg=adt">Eclipse ADT
+install</a> or <a href="{@docRoot}sdk/installing/index.html?pkg=tools">stand-alone SDK Tools
+install</a> instructions.</p>
+
+
+<p>Before you set up Android Studio, be sure you have installed
+JDK 6 or greater (the JRE alone is not sufficient). To check if you
+have JDK installed (and which version), open a terminal and type <code>javac -version</code>.
+If the JDK is not available or the version is lower than 6,
+<a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html" class="external-link"
+>go download JDK</a>.</p>
+
+
+<div class="procedure-box">
+
+<p id="instructions-toggle"
+style="float:right;font-size:13px"><a href='' onclick='showAll();return false;'
+>[ Show instructions for all platforms ]</a></p>
+
+<div class="win docs" style="display:none">
+
+<p><b>To set up Android Studio on Windows:</b></p>
+ <ol>
+ <li>Launch the downloaded EXE file, {@code android-studio-bundle-<version>.exe}.</li>
+ <li>Follow the setup wizard to install Android Studio.
+
+ <p>On some Windows systems, the launcher script does not find where Java is installed.
+ If you encounter this problem,
+ you need to set an environment variable indicating the correct location.</p>
+ <p>Select <strong>Start menu > Computer > System Properties >
+ Advanced System Properties</strong>. Then open <strong>Advanced tab > Environment
+ Variables</strong> and add a new system variable <code>JAVA_HOME</code> that points to
+ your JDK folder, for example <code>C:\Program Files\Java\jdk1.7.0_21</code>.</p>
+ </p>
+ </li>
+
+ </ol>
+
+
+<p>The individual tools and
+other SDK packages are saved within the Android Studio application directory.
+If you need to access the tools directly, use a terminal to navigate into the application and locate
+the {@code sdk/} directory. For example:</p>
+<p><code>\Users\<user>\AppData\Local\Android\android-studio\sdk\</code></p>
+
+
+
+</div><!-- end windows -->
+
+
+<div class="mac docs" style="display:none">
+
+<p><b>To set up Android Studio on Mac OSX:</b></p>
+ <ol>
+ <li>Open the downloaded DMG file, {@code android-studio-bundle-<version>.dmg}.</li>
+ <li>Drag and drop Android Studio into the Applications folder.
+ <p>
+ Depending on your security settings, when you attempt to open Android Studio, you might
+ see a warning that says the package is damaged and should be moved to the trash. If this
+ happens, go to <strong>System Preferences > Security & Privacy</strong> and under
+ <strong>Allow applications downloaded from</strong>, select <strong>Anywhere</strong>.
+ Then open Android Studio again.</p>
+ </li>
+ </ol>
+
+<p>The individual tools and
+other SDK packages are saved within the Android Studio application directory.
+If you need access the tools directly, use a terminal to navigate into the application and locate
+the {@code sdk/} directory. For example:</p>
+<p><code>/Applications/Android\ Studio.app/sdk/</code></p>
+
+
+</div><!-- end mac -->
+
+
+<div class="linux docs" style="display:none">
+
+<p><b>To set up Android Studio on Linux:</b></p>
+
+ <ol>
+ <li>Unpack the downloaded Tar file, {@code android-studio-bundle-<version>.tgz}, into an appropriate
+ location for your applications.
+ <li>To launch Android Studio, navigate to the {@code android-studio/bin/} directory
+ in a terminal and execute {@code studio.sh}.
+ <p>You may want to add {@code android-studio/bin/} to your PATH environmental
+ variable so that you can start Android Studio from any directory.</p>
+ </li>
+ </ol>
+
+</div><!-- end linux -->
+</div><!-- end procedure box -->
+
+<p>Android Studio is now ready and loaded with the Android developer tools, but there are still a
+couple packages you should add to make your Android SDK complete.</p>
+
+<p class="paging-links">
+<a href="{@docRoot}sdk/installing/adding-packages.html" class="next-page-link">
+Continue: Adding SDK Packages</a></p>
+
+
+</div>
+<!-- ################ END STUDIO ##################### -->
+
+
+
+
+
+
+
+
+
+<!-- ################ JUST SDK TOOLS ##################### -->
+<div id="tools" heading="Installing the Stand-alone SDK Tools" style="display:none">
+
+
+<p>The stand-alone SDK Tools package does not include a complete Android development environment.
+It includes only the core SDK tools, which you can access from a command line or with a plugin
+for your favorite IDE (if available).</p>
+
+<p>If you didn't download the SDK tools, go <a href="{@docRoot}sdk/index.html"
+><b>download the SDK now</b></a>,
+or switch to the <a href="{@docRoot}sdk/installing/index.html?pkg=adt">Eclipse ADT
+install</a> or <a href="{@docRoot}sdk/installing/index.html?pkg=studio">Android Studio
+install</a> instructions.</p>
+
+
+<div class="procedure-box">
+<p id="instructions-toggle"
+style="float:right;font-size:13px"><a href='' onclick='showAll();return false;'
+>[ Show instructions for all platforms ]</a></p>
+
+<div class="win docs" style="display:none">
+
+<p><b>To get started on Windows:</b></p>
+
<p>Your download package is an executable file that starts an installer. The installer checks your machine
for required tools, such as the proper Java SE Development Kit (JDK) and installs it if necessary.
The installer then saves the Android SDK Tools into a default location (or you can specify the location).</p>
@@ -21,15 +215,9 @@
<ol>
<li>Double-click the executable ({@code .exe} file) to start the install.</li>
<li>Make a note of the name and location in which it saves the SDK on your system—you will need to
-refer to the SDK directory later, when setting up the ADT plugin and when using
+refer to the SDK directory later when using
the SDK tools from the command line.</li>
-<li>Once the installation completes, the installer offers to start the Android SDK Manager.
-If you'll be using Eclipse, <strong>do not</strong> start the Android SDK Manager,
-and instead move on to <a href="{@docRoot}sdk/installing/installing-adt.html"
->Installing the Eclipse Plugin</a>.
-<p>If you're using a different IDE,
-start the SDK Manager and read <a href="{@docRoot}sdk/installing/adding-packages.html"
->Adding Platforms and Packages</a>.</p>
+<li>Once the installation completes, the installer starts the Android SDK Manager.
</li>
</ol>
@@ -37,51 +225,37 @@
-<div id="mac" class="docs" style="display:none">
+<div class="mac docs" style="display:none">
-<h3>Getting started on Mac</h3>
+<p><b>To get started on Mac OSX:</b></p>
-<ol>
-<li>Unpack the ZIP file you've downloaded. By default, it's unpacked
+<p>Unpack the ZIP file you've downloaded. By default, it's unpacked
into a directory named <code>android-sdk-mac_x86</code>. Move it to an appropriate location on your machine,
-such as a "Development" directory in your home directory.
+such as a "Development" directory in your home directory.</p>
<p>Make a note of the name and location of the SDK directory on your system—you will need to
-refer to the SDK directory later, when setting up the ADT plugin and when using
+refer to the SDK directory later when using
the SDK tools from the command line.</p>
-</li>
-<li>If you're using Eclipse, move on to <a href="{@docRoot}sdk/installing/installing-adt.html"
->Installing the Eclipse Plugin</a>. Otherwise, if you're using a different IDE,
-read <a href="{@docRoot}sdk/installing/adding-packages.html"
->Adding Platforms and Packages</a>.</li>
-</ol>
</div>
-<div id="linux" class="docs" style="display:none">
+<div class="linux docs" style="display:none">
-<h3>Getting started on Linux</h3>
+<p><b>To get started on Linux:</b></p>
-<ol>
-<li>Unpack the {@code .tgz} file you've downloaded. By default, the SDK files are unpacked
+<p>Unpack the {@code .tgz} file you've downloaded. By default, the SDK files are unpacked
into a directory named <code>android-sdk-linux_x86</code>. Move it to an appropriate location on your machine,
-such as a "Development" directory in your home directory.
+such as a "Development" directory in your home directory.</p>
<p>Make a note of the name and location of the SDK directory on your system—you will need to
-refer to the SDK directory later, when setting up the ADT plugin and when using
+refer to the SDK directory later when using
the SDK tools from the command line.</p>
-</li>
-<li>If you're using Eclipse, move on to <a href="{@docRoot}sdk/installing/installing-adt.html"
->Installing the Eclipse Plugin</a>. Otherwise, if you're using a different IDE,
-read <a href="{@docRoot}sdk/installing/adding-packages.html"
->Adding Platforms and Packages</a>.</li>
-</ol>
-<h5 id="Troubleshooting"><a href='' class="expandable"
+<h5 id="Troubleshooting" style="margin-bottom:15px"><a href='' class="expandable"
onclick="toggleExpandable(this,'#ubuntu-trouble');return false;"
>Troubleshooting Ubuntu</a></h5>
@@ -122,38 +296,129 @@
</div><!-- end ubuntu trouble -->
+</div><!-- end linux -->
+</div><!-- end procedure box -->
+
+
+<p>The Android SDK tools are now ready to begin developing apps, but there are still a
+couple packages you should add to make your Android SDK complete.</p>
+
+<p class="paging-links">
+<a href="{@docRoot}sdk/installing/adding-packages.html" class="next-page-link">
+Continue: Adding SDK Packages</a></p>
+
+
+</div>
+<!-- ################ END JUST TOOLS ##################### -->
+
+
+
+
+
+<!-- ################ DEFAULT ##################### -->
+<style>
+h3.large-link {
+ display:inline-block;
+ width:100%;
+ text-align:center;
+ border:1px solid #258aaf;
+ padding:10px 0;
+ color:inherit;
+}
+</style>
+
+<div id="default" style="display:none">
+
+<p>If you haven't already done so, <b><a href="{@docRoot}sdk/index.html">click here to download
+the Android SDK</a></b>. </p>
+
+<p>Otherwise, select which SDK package you want to install:</p>
+
+<div class="cols" style="margin-bottom:60px">
+<div class="col-4">
+<a href="{@docRoot}sdk/installing/index.html?pkg=adt">
+<h3 class="large-link">Eclipse ADT</h3>
+</a>
</div>
-<p style="margin-top:2em;"><a href='' onclick='showAll();return false;'>Information for other platforms</a></p>
+<div class="col-4">
+<a href="{@docRoot}sdk/installing/index.html?pkg=studio">
+<h3 class="large-link">Android Studio</h3></a>
+</div>
+
+<div class="col-4">
+<a href="{@docRoot}sdk/installing/index.html?pkg=tools">
+<h3 class="large-link">Stand-alone SDK Tools</h3></a>
+</div>
+</div>
+
+
+</div>
+<!-- ################ END DEFAULT ##################### -->
+
+
+
+
+
<script>
- var $osDocs;
- if (navigator.appVersion.indexOf("Win")!=-1) {
- $osDocs = $('#win');
- } else if (navigator.appVersion.indexOf("Mac")!=-1) {
- $osDocs = $('#mac');
- } else if (navigator.appVersion.indexOf("Linux")!=-1) {
- $osDocs = $('#linux');
- }
- if ($osDocs.length) {
- // reveal only the docs for this OS
- $osDocs.show();
- } else {
- // not running a compatible OS, so just show all the docs
- $('.docs').show();
- }
+// Show proper instructions based on downloaded SDK package
+var package = getUrlParam("pkg");
+if (package == "tools") {
+ // Show the SDK Tools (other IDE) instructions
+ $("h1").text($("#tools").attr('heading'));
+ $("#tools").show();
+} else if (package == "adt") {
+ // Show the ADT instructions
+ $("h1").text($("#adt").attr('heading'));
+ $("#adt").show();
+} else if (package == "studio") {
+ // Show the Android Studio instructions
+ $("h1").text($("#studio").attr('heading'));
+ $("#studio").show();
+} else {
+ // Show the default page content so user can select their setup
+ $("#default").show();
+}
- function showAll() {
- $('.docs').each(function() {
- if (!$(this).is(':visible')) {
- console.log('show')
- $(this).show();
- } else {
- console.log('hide')
- $(this).hide();
- $osDocs.show();
- }
- });
+// Show the proper instructions based on machine OS
+var $osDocs;
+if (navigator.appVersion.indexOf("Win")!=-1) {
+ $osDocs = $('.win');
+} else if (navigator.appVersion.indexOf("Mac")!=-1) {
+ $osDocs = $('.mac');
+} else if (navigator.appVersion.indexOf("Linux")!=-1) {
+ $osDocs = $('.linux');
+}
+
+if ($osDocs.length) {
+ // reveal only the docs for this OS
+ $osDocs.show();
+} else {
+ // not running a compatible OS, so just show all the docs
+ $('.docs').show();
+}
+
+
+/* Shows all the machine OS instructions */
+function showAll() {
+ $('.docs').show();
+ $("#instructions-toggle").hide();
+}
+
+/* Returns the value for the given URL parameter */
+function getUrlParam(param) {
+ var url = window.location.search.substring(1);
+ var variables = url.split('&');
+ for (var i = 0; i < variables.length; i++) {
+ var paramName = variables[i].split('=');
+ if (escape(paramName[0]) == param) {
+ return escape(paramName[1]);
+ }
}
+}
+
+
+
</script>
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index 7bf366c..1e87cd8 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -15,19 +15,28 @@
UI, debug your app, and export signed (or unsigned) app packages (APKs) for distribution.
</p>
-<p>If you need to install Eclipse, you can download it from <a href=
-"http://www.eclipse.org/downloads/">eclipse.org/downloads/</a>.</p>
+<p class="note"><strong>Note:</strong> You should install the ADT plugin
+only if you already have an Eclipse installation that you want to continue using. If you do not
+have Eclipse installed, you should instead <b><a href="{@docRoot}sdk/index.html">install
+the complete Android SDK</a></b>, which includes the latest IDE for Android developers.</p>
-
-<p class="note"><strong>Note:</strong> If you prefer to work in a different IDE, you do not need to
-install Eclipse or ADT. Instead, you can directly use the SDK tools to build and
-debug your application.</p>
-
+<p>Your existing Eclipse installation must meet these requirements:</p>
+ <ul>
+ <li><a href="http://eclipse.org/mobile/">Eclipse</a> 3.7.2 (Indigo) or greater
+<p class="note"><strong>Note:</strong> Eclipse 3.6 (Helios) is no longer
+supported with the latest version of ADT.</p></li>
+ <li>Eclipse <a href="http://www.eclipse.org/jdt">JDT</a> plugin (included
+in most Eclipse IDE packages) </li>
+ <li><a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">JDK 6</a>
+ (JRE alone is not sufficient)</li>oid Development Tools plugin</a>
+(recommended)</li>
+ <li><strong>Not</strong> compatible with GNU Compiler for Java (gcj)</li>
+ </ul>
<h2 id="Download">Download the ADT Plugin</h2>
-
+<p>To add the ADT plugin to Eclipse:</p>
<ol>
<li>Start Eclipse, then select <strong>Help</strong> > <strong>Install New
Software</strong>.</li>
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index 1b47f7f..8ac6163 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -1,5 +1,5 @@
-page.title=Getting Started with Android Studio
-page.tags=studio
+page.title=Android Studio
+page.tags="studio"
@jd:body
@@ -7,7 +7,7 @@
<div style="position:relative;min-height:660px;">
-<h3 style="color:#f80">EARLY ACCESS PREVIEW</h3>
+<h3 style="color:#FF4444;margin:-30px 0 20px">BETA</h3>
<div id="tos" style="position:absolute;display:none;width:inherit;">
<div class="col-13" style="margin:0;"> </div><!-- provides top margin for content -->
@@ -183,23 +183,21 @@
-
-
<div id="main">
-<div class="figure" style="width:400px;margin-top:-20px">
+<div class="figure" style="width:400px;margin-top:-75px">
<img src="{@docRoot}images/tools/android-studio.png" height="330" width="400" style="margin-bottom:20px" />
<a class="big button subtitle" id="download-ide-button"
-href="" style="display:none;width:265px;margin:0 auto;display:block;font-size:18px" ></a>
-<div style="width:290px;padding:10px 40px 0 60px;font-size:12px;line-height:16px">
+href="" style="display:none;width:368px;margin:0 auto;display:block;font-size:18px" ></a>
+<div style="margin:20px 0 0 0">
<p style="margin-bottom:8px">This download includes:</p>
-<ul>
-<li>Android Studio <b>early access preview</b></li>
-<li>All the Android SDK Tools to design, test, debug, and profile your app</li>
-<li>The latest Android platform to compile your app</li>
-<li>The latest Android system image to run your app in the emulator</li>
+<ul style="margin-bottom:20px">
+<li>Android Studio Beta</li>
+<li>All the Android SDK Tools to design, test, and debug your app</li>
+<li>A version of the Android platform to compile your app</li>
+<li>A version of the Android system image to run your app in the emulator</li>
</ul>
</div>
@@ -208,36 +206,34 @@
<p>Android Studio is a new Android development environment based on IntelliJ
-IDEA. Similar to Eclipse with the
-ADT Plugin, Android Studio provides integrated Android developer tools
-for development and debugging. On top of the
+IDEA. It provides new features and improvements over Eclipse ADT
+and will be the official Android IDE once it's ready. On top of the
capabilities you expect from IntelliJ, Android Studio offers:</p>
<ul>
- <li>Gradle-based build support.</li>
- <li>Android-specific refactoring and quick fixes.</li>
- <li>Lint tools to catch performance, usability, version compatibility and other problems.</li>
- <li>ProGuard and app-signing capabilities. </li>
- <li>Template-based wizards to create common Android designs and components.</li>
- <li>A rich layout editor that allows you to drag-and-drop UI components, preview layouts on
- multiple screen configurations, and much more.</li>
+ <li>Flexible Gradle-based build system.</li>
+ <li>Build variants and multiple APK generation.</li>
+ <li>Expanded template support for Google Services and various device types.</li>
+ <li>Rich layout editor with support for theme editing.</li>
+ <li>Lint tools to catch performance, usability, version compatibility, and other problems.</li>
+ <li>ProGuard and app-signing capabilities.</li>
<li>Built-in support for <a
href="http://android-developers.blogspot.com/2013/06/adding-backend-to-your-app-in-android.html"
class="external-link">Google Cloud Platform</a>, making it easy to integrate Google Cloud
- Messaging and App Engine as server-side components.
+ Messaging and App Engine.
</ul>
-<p class="caution"><strong>Caution:</strong> Android Studio is currently available as
-an <strong>early access preview</strong>. Several features
-are either incomplete or not yet implemented and you may encounter bugs. If you are not
+<p class="caution"><strong>Caution:</strong> Android Studio is currently in
+<strong>beta</strong>. Some features
+are not yet implemented and you may encounter bugs. If you are not
comfortable using an unfinished product, you may want to instead
-download (or continue to use) the
-<a href="{@docRoot}sdk/index.html">ADT Bundle</a> (Eclipse with the ADT Plugin).</p>
+download (or continue to use)
+<a href="{@docRoot}sdk/index.html">Eclipse with ADT</a>.</p>
-<h4 style="clear:right;text-align:right;margin-right:50px"><a href='' class="expandable"
+<h4 style="margin-top: 20px;"><a href='' class="expandable"
onclick="toggleExpandable(this,'.pax');return false;"
- >DOWNLOAD FOR OTHER PLATFORMS</a></h4>
+ >VIEW ALL DOWNLOADS AND SIZES</a></h4>
<div class="pax col-13 online" style="display:none;margin:0;">
@@ -290,6 +286,73 @@
+<h2 style="margin-bottom: 0px;">Android Studio vs. Eclipse ADT Comparison</h2>
+
+<p>
+The following table lists some key differences between Android Studio Beta and
+<a href="{@docRoot}sdk/index.html">Eclipse with ADT</a>.
+</p>
+
+<style>
+td.yes {
+ color: #669900;
+}
+td.no {
+ color: #CC0000;
+}
+</style>
+
+<table>
+ <tbody><tr>
+ <th>Feature</th>
+ <th>Android Studio</th>
+ <th>ADT</th>
+ </tr>
+ <tr>
+ <td>Build system</td>
+ <td><a href="http://www.gradle.org/" class="external-link">Gradle</a></td>
+ <td><a href="http://ant.apache.org/" class="external-link">Ant</a></td>
+ </tr>
+ <tr>
+
+ <td>Maven-based build dependencies</td>
+ <td class="yes">Yes</td>
+ <td class="no">No</td>
+ </tr>
+
+ <td>Build variants and multiple-APK generation (great for Android Wear)</td>
+ <td class="yes">Yes</td>
+ <td class="no">No</td>
+ </tr>
+
+ <tr>
+ <td>Advanced Android code completion and refactoring</td>
+ <td class="yes">Yes</td>
+ <td class="no">No</td>
+ </tr>
+ <tr>
+ <td>Graphical layout editor</td>
+ <td class="yes">Yes</td>
+ <td class="yes">Yes</td>
+ </tr>
+ <tr>
+ </tr>
+
+ <tr>
+ <td>APK signing and keystore management</td>
+ <td class="yes">Yes</td>
+ <td class="yes">Yes</td>
+ </tr>
+
+ <tr>
+ <td>NDK support</td>
+ <td class="no">Coming soon</td>
+ <td class="yes">Yes</td>
+ </tr>
+ </tbody></table>
+
+
+
<h2 id="Updating">Updating from older versions</h2>
<p>If you already have Android Studio installed, in most cases, you can upgrade to the latest
@@ -298,7 +361,7 @@
Check for updates</strong>) to see whether an update is available.</p>
<p>If an update is not available,
-follow the <a href="#Installing">installation instructions</a> below and replace your existing
+click the button above to download and replace your existing
installation.</p>
<div class="caution">
@@ -311,100 +374,6 @@
the Android SDK Manager.</p>
</div>
-
-<h2 id="Installing">Installing Android Studio</h2>
-<p>Android Studio requires JDK 6 or greater (JRE alone is not sufficient). To check if you
-have JDK installed (and which version), open a terminal and type <code>javac -version</code>.
-If JDK is not available or the version is lower than 6,
-<a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">download
-JDK from here</a>.</p>
-<p>To install Android Studio:</p>
-<ol>
-<li>Download the <strong>Android Studio</strong> package from above.</li>
-<li>Install Android Studio and the SDK tools:
- <p><b>Windows:</b></p>
- <ol>
- <li>Launch the downloaded EXE file, {@code android-studio-bundle-<version>.exe}.</li>
- <li>Follow the setup wizard to install Android Studio.
-
- <div class="caution"><p><strong>Known issue:</strong>
- On some Windows systems, the launcher script does not find where Java is installed.
- If you encounter this problem,
- you need to set an environment variable indicating the correct location.</p>
- <p>Select <strong>Start menu > Computer > System Properties >
- Advanced System Properties</strong>. Then open <strong>Advanced tab > Environment
- Variables</strong> and add a new system variable <code>JAVA_HOME</code> that points to
- your JDK folder, for example <code>C:\Program Files\Java\jdk1.7.0_21</code>.</p>
- </div>
- </li>
-
- </ol>
- <p><b>Mac OS X:</b></p>
- <ol>
- <li>Open the downloaded DMG file, {@code android-studio-bundle-<version>.dmg}.</li>
- <li>Drag and drop Android Studio into the Applications folder.
-
- <div class="caution"><p><strong>Known issue:</strong>
- Depending on your security settings, when you attempt to open Android Studio, you might
- see a warning that says the package is damaged and should be moved to the trash. If this
- happens, go to <strong>System Preferences > Security & Privacy</strong> and under
- <strong>Allow applications downloaded from</strong>, select <strong>Anywhere</strong>.
- Then open Android Studio again.</p>
- </div>
- </li>
-
- </ol>
- <p><b>Linux:</b></p>
- <ol>
- <li>Unpack the downloaded Tar file, {@code android-studio-bundle-<version>.tgz}, into an appropriate
- location for your applications.
- <li>To launch Android Studio, navigate to the {@code android-studio/bin/} directory
- in a terminal and execute {@code studio.sh}.
- <p>You may want to add {@code android-studio/bin/} to your PATH environmental
- variable so that you can start Android Studio from any directory.</p>
- </li>
- </ol>
-</li>
-</ol>
-
-<p>That's it! You're ready to start developing apps with Android Studio.</p>
-
-<div class="note">
-<p><strong>Note:</strong> On Windows and Mac, the individual tools and
-other SDK packages are saved within the Android Studio application directory.
-To access the tools directly, use a terminal to navigate into the application and locate
-the {@code sdk/} directory. For example:</p>
-<p>Windows: <code>\Users\<user>\AppData\Local\Android\android-studio\sdk\</code></p>
-<p>Mac: <code>/Applications/Android\ Studio.app/sdk/</code></p>
-</div>
-
-<p>For a list of some known issues, see <a
-href="http://tools.android.com/knownissues">tools.android.com/knownissues</a>.</p>
-
-
-<h2 id="Start">Starting a Project</h2>
-
-<p>When you launch Android Studio for the first time, you'll see a Welcome
-screen that offers several ways to get started:</p>
-
-<ul>
- <li>To start building a new app, click <strong>New Project</strong>.
- <p>This starts the New Project wizard, which helps you set up a project using an app template.
- </li>
- <li>To import an existing Android app project, click <strong>Import Project</strong>.
- <p class="note"><strong>Note:</strong> If you previously developed your Android project
- with Eclipse, you should first use the new export feature in the ADT plugin to prepare
- your project with the new Gradle build system. For more information, read
- <a href="{@docRoot}sdk/installing/migrate.html">Migrating from Eclipse</a> and
- <a href="{@docRoot}sdk/installing/studio-build.html">Building Your Project with
- Gradle</a>.</p>
- </li>
-</ul>
-
-<p>For additional help using Android Studio, read <a
-href="{@docRoot}sdk/installing/studio-tips.html">Tips and Tricks</a>.</p>
-
-
<p>As you continue developing apps, you may need to install additional versions
of Android for the emulator and other packages such as the <a
href="{@docRoot}tools/support-library/index.html">Android Support Library</a>.
@@ -601,8 +570,8 @@
if (os) {
/* set up primary ACE download button */
$('#download-ide-button').show();
- $('#download-ide-button').append("Download Android Studio <span class='small'>v0.5.2</span>"
- + "<br/> <span class='small'>for " + os + "</span>");
+ $('#download-ide-button').append("Download Android Studio Beta <span class='small'>v0.5.2</span>"
+ + "<br/> <span class='small'>with the Android SDK for " + os + "</span>");
$('#download-ide-button').click(function() {return onDownload(this,true);}).attr('href', bundlename);
} else {
@@ -644,9 +613,13 @@
function onDownloadForRealz(link) {
if ($("input#agree").is(':checked')) {
- $("#tos").hide();
- $("#main").show();
- location.hash = "Updating";
+ $("h1").text('Now redirecting to the install instructions...');
+ $("#tos").slideUp();
+ $("#jd-content .jd-descr").fadeOut('slow', function() {
+ setTimeout(function() {
+ window.location = "/sdk/installing/index.html?pkg=studio";
+ }, 1000);
+ });
_gaq.push(['_trackEvent', 'SDK', 'Android Studio', $("#downloadForRealz").html()]);
return true;
} else {
diff --git a/docs/html/tools/device.jd b/docs/html/tools/device.jd
index e748b12..89b3857 100644
--- a/docs/html/tools/device.jd
+++ b/docs/html/tools/device.jd
@@ -5,6 +5,7 @@
<div id="qv">
<h2>In this document</h2>
<ol>
+ <li><a href="#device-developer-options">Enabling On-device Developer Options</a></li>
<li><a href="#setting-up">Setting up a Device for Development</a>
<ol>
<li><a href="#VendorIds">USB Vendor IDs</a></li>
@@ -43,6 +44,29 @@
platform, in different screen sizes and orientations, and more.</p>
+<h2 id="developer-device-options" style="margin-bottom: 0px;">Enabling On-device Developer Options</h2>
+
+<img src="/images/tools/dev-options-inmilk.png" alt="" style="float:right;margin-left:30px">
+
+<p>Android-powered devices have a host of developer options that you can
+access on the phone, which let you:</p>
+<ul>
+ <li>Enable debugging over USB.</li>
+ <li>Quickly capture bug reports onto the device.</li>
+ <li>Show CPU usage on screen.</li>
+ <li>Draw debugging information on screen such as layout bounds,
+ updates on GPU views and hardware layers, and other information.</li>
+ <li>Plus many more options to simulate app stresses or enable debugging options.</li>
+</ul>
+<p>To access these settings, open the <em>Developer options</em> in the
+system Settings. On Android 4.2 and higher, the Developer options screen is
+hidden by default. To make it visible, go to
+<b>Settings > About phone</b> and tap <b>Build number</b> seven times. Return to the previous
+screen to find Developer options at the bottom.</p>
+
+
+
+
<h2 id="setting-up">Setting up a Device for Development</h2>
<p>With an Android-powered device, you can develop and debug your Android applications just as you
diff --git a/docs/html/tools/help/sdk-manager.jd b/docs/html/tools/help/sdk-manager.jd
index 57271bb..b084237 100644
--- a/docs/html/tools/help/sdk-manager.jd
+++ b/docs/html/tools/help/sdk-manager.jd
@@ -3,7 +3,9 @@
<p>The Android SDK separates tools, platforms, and other components into packages you can
- download using the SDK Manager.</p>
+ download using the SDK Manager. For example, when the SDK Tools are updated or a new version of
+the Android platform is released, you can use the SDK Manager to quickly download them to
+your environment.</p>
<p>You can launch the SDK Manager in one of the following ways:</p>
<ul>
@@ -25,6 +27,14 @@
SDK packages that are available, already installed, or for which an update is available.</p>
+<p>There are several different packages available for the Android SDK. The table below describes
+most of the available packages and where they're located in your SDK directory
+once you download them.</p>
+
+
+
+
+
<h2 id="Recommended">Recommended Packages</h2>
<p>Here's an outline of the packages required and those we recommend you use:
@@ -69,3 +79,77 @@
<p class="note"><strong>Tip:</strong> For easy access to the SDK tools from a command line, add the
location of the SDK's <code>tools/</code> and
<code>platform-tools</code> to your <code>PATH</code> environment variable.</p>
+
+
+<p>The above list is not comprehensive and you can <a
+href="#AddingSites">add new sites</a> to download additional packages from third-parties.</p>
+
+<p>In some cases, an SDK package may require a specific minimum revision of
+another package or SDK tool.
+The development tools will notify you with warnings if there is dependency that you need to
+address. The Android SDK Manager also enforces dependencies by requiring that you download any
+packages that are needed by those you have selected.</p>
+
+
+
+
+
+<h2 id="AddingSites">Adding New Sites</h2>
+
+<p>By default, <strong>Available Packages</strong> displays packages available from the
+<em>Android Repository</em> and <em>Third party Add-ons</em>. You can add other sites that host
+their own Android SDK add-ons, then download the SDK add-ons
+from those sites.</p>
+
+<p>For example, a mobile carrier or device manufacturer might offer additional
+API libraries that are supported by their own Android-powered devices. In order
+to develop using their libraries, you must install their Android SDK add-on, if it's not already
+available under <em>Third party Add-ons</em>. </p>
+
+<p>If a carrier or device manufacturer has hosted an SDK add-on repository file
+on their web site, follow these steps to add their site to the Android SDK
+Manager:</p>
+
+<ol>
+ <li>Select <strong>Available Packages</strong> in the left panel.</li>
+ <li>Click <strong>Add Add-on Site</strong> and enter the URL of the
+<code>repository.xml</code> file. Click <strong>OK</strong>.</li>
+</ol>
+<p>Any SDK packages available from the site will now be listed under a new item named
+<strong>User Add-ons</strong>.</p>
+
+
+
+
+<h2 id="troubleshooting">Troubleshooting</h2>
+
+<p><strong>Problems connecting to the SDK repository</strong></p>
+
+<p>If you are using the Android SDK Manager to download packages and are encountering
+connection problems, try connecting over http, rather than https. To switch the
+protocol used by the Android SDK Manager, follow these steps: </p>
+
+<ol>
+ <li>With the Android SDK Manager window open, select "Settings" in the
+ left pane. </li>
+ <li>On the right, in the "Misc" section, check the checkbox labeled "Force
+ https://... sources to be fetched using http://..." </li>
+ <li>Click <strong>Save & Apply</strong>.</li>
+</ol>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index b29b87c..fb4659f 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -1,53 +1,35 @@
<ul id="nav">
<li class="nav-section">
- <div class="nav-section-header empty">
- <a href="<?cs var:toroot ?>tools/index.html"><span class="en">Developer Tools</span></a>
- </div>
- </li>
-
- <li class="nav-section">
<div class="nav-section-header"><a href="<?cs var:toroot
?>sdk/index.html"><span class="en">Download</span></a></div>
<ul>
- <li><a href="<?cs var:toroot ?>sdk/installing/bundle.html">
- <span class="en">Setting Up the ADT Bundle</span></a></li>
+ <li><a href="<?cs var:toroot ?>sdk/installing/index.html">
+ <span class="en">Installing the SDK</span></a></li>
- <li class="nav-section">
- <div class="nav-section-header">
- <a href="<?cs var:toroot ?>sdk/installing/index.html"><span class="en">Setting Up
- an Existing IDE</span></a></div>
- <ul>
- <li><a href="<?cs var:toroot ?>sdk/installing/installing-adt.html">
- <span class="en">Installing the Eclipse Plugin</span></a></li>
- <li><a href="<?cs var:toroot ?>sdk/installing/adding-packages.html">
- <span class="en">Adding Platforms and Packages</span></a></li>
- </ul>
- </li>
-
- <li class="nav-section">
- <div class="nav-section-header">
- <a href="<?cs var:toroot ?>sdk/installing/studio.html">Android Studio</a>
- </div>
- <ul>
- <li><a href="<?cs var:toroot ?>sdk/installing/migrate.html">
- Migrating from Eclipse</a></li>
- <li><a href="<?cs var:toroot ?>sdk/installing/studio-tips.html">
- Tips and Tricks</a></li>
- <li><a href="<?cs var:toroot ?>sdk/installing/studio-layout.html">
- Using the Layout Editor</a></li>
- <li><a href="<?cs var:toroot ?>sdk/installing/studio-build.html">
- Building Your Project with Gradle</a></li>
- <li><a href="<?cs var:toroot ?>sdk/installing/studio-debug.html">
- Debugging with Android Studio</a></li>
- </ul>
- </li>
- <li><a href="<?cs var:toroot ?>sdk/exploring.html">
- <span class="en">Exploring the SDK</span></a></li>
- <li><a href="<?cs var:toroot ?>tools/sdk/ndk/index.html">Download the NDK</a>
- </li>
+ <li><a href="<?cs var:toroot ?>sdk/installing/adding-packages.html">
+ <span class="en">Adding SDK Packages</span></a></li>
</ul>
</li>
+
+
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>sdk/installing/studio.html">Android Studio</a>
+ </div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>sdk/installing/migrate.html">
+ Migrating from Eclipse</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/installing/studio-tips.html">
+ Tips and Tricks</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/installing/studio-layout.html">
+ Using the Layout Editor</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/installing/studio-build.html">
+ Building Your Project with Gradle</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/installing/studio-debug.html">
+ Debugging with Android Studio</a></li>
+ </ul>
+ </li>
<li class="nav-section">
<div class="nav-section-header">
@@ -174,7 +156,13 @@
class="en">Tools Help</span></a></div>
<ul>
<li><a href="<?cs var:toroot ?>tools/help/adb.html">adb</a></li>
- <li><a href="<?cs var:toroot ?>tools/help/adt.html">ADT</a></li>
+ <li class="nav-section">
+ <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/help/adt.html">ADT</a></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>sdk/installing/installing-adt.html">
+ <span class="en">Installing the Eclipse Plugin</span></a></li>
+ </ul>
+ </li>
<li><a href="<?cs var:toroot ?>tools/help/android.html">android</a></li>
<li><a href="<?cs var:toroot ?>tools/help/avd-manager.html">AVD Manager</a></li>
<li><a href="<?cs var:toroot ?>tools/help/bmgr.html">bmgr</a>
@@ -244,6 +232,11 @@
</ul>
</li>
+ <li class="nav-section">
+ <div class="nav-section-header empty">
+ <a href="<?cs var:toroot ?>tools/sdk/ndk/index.html">NDK</a>
+ </div>
+ </li>
<li class="nav-section">
<div class="nav-section-header">
diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd
new file mode 100644
index 0000000..bbbda67
--- /dev/null
+++ b/docs/html/training/articles/keystore.jd
@@ -0,0 +1,107 @@
+page.title=Android Keystore System
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#WhichShouldIUse">Choosing Between a Keychain or the Android Keystore Provider</a></li>
+ <li><a href="#UsingAndroidKeyStore">Using Android Keystore Provider
+ </a></li>
+ <ol>
+ <li><a href="#GeneratingANewPrivateKey">Generating a New Private Key</a></li>
+ <li><a href="#WorkingWithKeyStoreEntries">Working with Keystore Entries</a></li>
+ <li><a href="#ListingEntries">Listing Entries</a></li>
+ <li><a href="#SigningAndVerifyingData">Signing and Verifying Data</a></li>
+ </ol>
+ </ol>
+
+ <h2>Blog articles</h2>
+ <ol>
+ <li><a
+ href="http://android-developers.blogspot.com/2012/03/unifying-key-store-access-in-ics.html">
+ <h4>Unifying Key Store Access in ICS</h4>
+ </a></li>
+ </ol>
+ </div>
+</div>
+
+<p>The Android Keystore system lets you store private keys
+ in a container to make it more difficult to extract from the
+ device. Once keys are in the keystore, they can be used for
+ cryptographic operations with the private key material remaining
+ non-exportable.</p>
+
+<p>The Keystore system is used by the {@link
+ android.security.KeyChain} API as well as the Android
+ Keystore provider feature that was introduced in Android 4.3
+ (API level 18). This document goes over when and how to use the
+ Android Keystore provider.</p>
+
+<h2 id="WhichShouldIUse">Choosing Between a Keychain or the
+Android Keystore Provider</h2>
+
+<p>Use the {@link android.security.KeyChain} API when you want
+ system-wide credentials. When an app requests the use of any credential
+ through the {@link android.security.KeyChain} API, users get to
+ choose, through a system-provided UI, which of the installed credentials
+ an app can access. This allows several apps to use the
+ same set of credentials with user consent.</p>
+
+<p>Use the Android Keystore provider to let an individual app store its own
+ credentials that only the app itself can access.
+ This provides a way for apps to manage credentials that are usable
+ only by itself while providing the same security benefits that the
+ {@link android.security.KeyChain} API provides for system-wide
+ credentials. This method requires no user interaction to select the credentials.</p>
+
+<h2 id="UsingAndroidKeyStore">Using Android Keystore Provider</h2>
+
+<p>
+To use this feature, you use the standard {@link java.security.KeyStore}
+and {@link java.security.KeyPairGenerator} classes along with the
+{@code AndroidKeyStore} provider introduced in Android 4.3 (API level 18).</p>
+
+<p>{@code AndroidKeyStore} is registered as a {@link
+ java.security.KeyStore} type for use with the {@link
+ java.security.KeyStore#getInstance(String) KeyStore.getInstance(type)}
+ method and as a provider for use with the {@link
+ java.security.KeyPairGenerator#getInstance(String, String)
+ KeyPairGenerator.getInstance(algorithm, provider)} method.</p>
+
+<h3 id="GeneratingANewPrivateKey">Generating a New Private Key</h3>
+
+<p>Generating a new {@link java.security.PrivateKey} requires that
+ you also specify the initial X.509 attributes that the self-signed
+ certificate will have. You can replace the certificate at a later
+ time with a certificate signed by a Certificate Authority.</p>
+
+<p>To generate the key, use a {@link java.security.KeyPairGenerator}
+ with {@link android.security.KeyPairGeneratorSpec}:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java generate}
+
+<h3 id="WorkingWithKeyStoreEntries">Working with Keystore Entries</h3>
+
+<p>Using the {@code AndroidKeyStore} provider takes place through
+ all the standard {@link java.security.KeyStore} APIs.</p>
+
+<h4 id="ListingEntries">Listing Entries</h4>
+
+<p>List entries in the keystore by calling the {@link
+ java.security.KeyStore#aliases()} method:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java list}
+
+<h4 id="SigningAndVerifyingData">Signing and Verifying Data</h4>
+
+<p>Sign data by fetching the {@link
+ java.security.KeyStore.Entry} from the keystore and using the
+ {@link java.security.Signature} APIs, such as {@link
+ java.security.Signature#sign()}:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java sign}
+
+<p>Similarly, verify data with the {@link java.security.Signature#verify(byte[])} method:</p>
+
+{@sample development/samples/ApiDemos/src/com/example/android/apis/security/KeyStoreUsage.java verify}
diff --git a/docs/html/training/cloudsync/backupapi.jd b/docs/html/training/cloudsync/backupapi.jd
index a5436c6..fd35ada 100644
--- a/docs/html/training/cloudsync/backupapi.jd
+++ b/docs/html/training/cloudsync/backupapi.jd
@@ -41,7 +41,7 @@
<h2 id="register">Register for the Android Backup Service</h2>
<p>This lesson requires the use of the <a
- href="http://code.google.com/android/backup/index.html">Android Backup
+ href="{@docRoot}google/backup/index.html">Android Backup
Service</a>, which requires registration. Go ahead and <a
href="http://code.google.com/android/backup/signup.html">register here</a>. Once
that's done, the service pre-populates an XML tag for insertion in your Android
diff --git a/docs/html/training/cloudsync/index.jd b/docs/html/training/cloudsync/index.jd
index eb7df3d..cf7117c 100644
--- a/docs/html/training/cloudsync/index.jd
+++ b/docs/html/training/cloudsync/index.jd
@@ -6,6 +6,16 @@
@jd:body
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
+<ul>
+ <li>Android 2.2 (API level 8) and higher</li>
+</ul>
+</div>
+</div>
+
<p>By providing powerful APIs for internet connectivity, the Android framework
helps you build rich cloud-enabled apps that sync their data to a remote web
service, making sure all your devices always stay in sync, and your valuable
diff --git a/docs/html/training/tv/index.jd b/docs/html/training/tv/index.jd
deleted file mode 100644
index a99e378..0000000
--- a/docs/html/training/tv/index.jd
+++ /dev/null
@@ -1,59 +0,0 @@
-page.title=Designing for TV
-page.tags=input,screens
-
-trainingnavtop=true
-startpage=true
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
-<h2>Dependencies and prerequisites</h2>
-<ul>
- <li>Android 2.0 (API Level 5) or higher</li>
-</ul>
-
-</div>
-</div>
-
-<a class="notice-developers-video wide" href="http://www.youtube.com/watch?v=zsRnRLh-O34">
-<div>
- <h3>Video</h3>
- <p>DevBytes: Design for Large Displays - Part 1</p>
-</div>
-</a>
-
-<p>
- Smart TVs powered by Android bring your favorite Android apps to the best screen in your house.
- Thousands of apps in the Google Play Store are already optimized for TVs. This class shows how
- you can optimize your Android app for TVs, including how to build a layout that
- works great when the user is ten feet away and navigating with a remote control.
-</p>
-
-<h2>Lessons</h2>
-
-<dl>
- <dt><b><a href="optimizing-layouts-tv.html">Optimizing Layouts for TV</a></b></dt>
- <dd>Shows you how to optimize app layouts for TV screens, which have some unique characteristics such as:
- <ul>
- <li>permanent "landscape" mode</li>
- <li>high-resolution displays</li>
- <li>"10 foot UI" environment.</li>
- </ul>
- </dd>
-
- <dt><b><a href="optimizing-navigation-tv.html">Optimizing Navigation for TV</a></b></dt>
- <dd>Shows you how to design navigation for TVs, including:
- <ul>
- <li>handling D-pad navigation</li>
- <li>providing navigational feedback</li>
- <li>providing easily-accessible controls on the screen.</li>
- </ul>
- </dd>
-
- <dt><b><a href="unsupported-features-tv.html">Handling features not supported on TV</a></b></dt>
- <dd>Lists the hardware features that are usually not available on TVs. This lesson also shows you how to
- provide alternatives for missing features or check for missing features and disable code at run time.</dd>
-</dl>
diff --git a/docs/html/training/tv/optimizing-layouts-tv.jd b/docs/html/training/tv/optimizing-layouts-tv.jd
deleted file mode 100644
index a6db052..0000000
--- a/docs/html/training/tv/optimizing-layouts-tv.jd
+++ /dev/null
@@ -1,246 +0,0 @@
-page.title=Optimizing Layouts for TV
-parent.title=Designing for TV
-parent.link=index.html
-
-trainingnavtop=true
-next.title=Optimizing Navigation for TV
-next.link=optimizing-navigation-tv.html
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
- <li><a href="#DesignLandscapeLayouts">Design Landscape Layouts</a></li>
- <li><a href="#MakeTextControlsEasyToSee">Make Text and Controls Easy to See</a></li>
- <li><a href="#DesignForLargeScreens">Design for High-Density Large Screens</a></li>
- <li><a href="#HandleLargeBitmaps">Design to Handle Large Bitmaps</a></li>
-</ol>
-
-<h2>You should also read</h2>
-<ul>
- <li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></li>
-</ul>
-
-</div>
-</div>
-
-<p>
-When your application is running on a television set, you should assume that the user is sitting about
-ten feet away from the screen. This user environment is referred to as the
-<a href="http://en.wikipedia.org/wiki/10-foot_user_interface">10-foot UI</a>. To provide your
-users with a usable and enjoyable experience, you should style and lay out your UI accordingly..
-</p>
-<p>
-This lesson shows you how to optimize layouts for TV by:
-</p>
-<ul>
- <li>Providing appropriate layout resources for landscape mode.</li>
- <li>Ensuring that text and controls are large enough to be visible from a distance.</li>
- <li>Providing high resolution bitmaps and icons for HD TV screens.</li>
-</ul>
-
-<h2 id="DesignLandscapeLayouts">Design Landscape Layouts</h2>
-
-<p>
-TV screens are always in landscape orientation. Follow these tips to build landscape layouts optimized for TV screens:
-</p>
-<ul>
- <li>Put on-screen navigational controls on the left or right side of the screen and save the
- vertical space for content.</li>
- <li>Create UIs that are divided into sections, by using <a href="{@docRoot}guide/components/fragments.html">Fragments</a>
- and use view groups like {@link android.widget.GridView} instead
- of {@link android.widget.ListView} to make better use of the
- horizontal screen space.</li>
- <li>Use view groups such as {@link android.widget.RelativeLayout}
- or {@link android.widget.LinearLayout} to arrange views.
- This allows the Android system to adjust the position of the views to the size, alignment,
- aspect ratio, and pixel density of the TV screen.</li>
- <li>Add sufficient margins between layout controls to avoid a cluttered UI.</li>
-</ul>
-
-<p>
-For example, the following layout is optimized for TV:
-</p>
-
-<img src="{@docRoot}images/training/panoramio-grid.png" />
-
-<p>
-In this layout, the controls are on the lefthand side. The UI is displayed within a
-{@link android.widget.GridView}, which is well-suited to landscape orientation.
-In this layout both GridView and Fragment have the width and height set
-dynamically, so they can adjust to the screen resolution. Controls are added to the left side Fragment programatically at runtime.
-The layout file for this UI is {@code res/layout-land-large/photogrid_tv.xml}.
-(This layout file is placed in {@code layout-land-large} because TVs have large screens with landscape orientation. For details refer to
-<a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>.)</p>
-
-res/layout-land-large/photogrid_tv.xml
-<pre>
-<RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="fill_parent" >
-
- <fragment
- android:id="@+id/leftsidecontrols"
- android:layout_width="0dip"
- android:layout_marginLeft="5dip"
- android:layout_height="match_parent" />
-
- <GridView
- android:id="@+id/gridview"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
-</RelativeLayout>
-</pre>
-
-<p>
-To set up action bar items on the left side of the screen, you can also include the <a
-href="http://code.google.com/p/googletv-android-samples/source/browse/#git%2FLeftNavBarLibrary">
-Left navigation bar library</a> in your application to set up action items on the left side
-of the screen, instead of creating a custom Fragment to add controls:
-</p>
-
-<pre>
-LeftNavBar bar = (LeftNavBarService.instance()).getLeftNavBar(this);
-</pre>
-
-<p>
-When you have an activity in which the content scrolls vertically, always use a left navigation bar;
-otherwise, your users have to scroll to the top of the content to switch between the content view and
-the ActionBar. Look at the
-<a href="http://code.google.com/p/googletv-android-samples/source/browse/#git%2FLeftNavBarDemo">
-Left navigation bar sample app</a> to see how to simple it is to include the left navigation bar in your app.
-</p>
-
-<h2 id="MakeTextControlsEasyToSee">Make Text and Controls Easy to See</h2>
-<p>
-The text and controls in a TV application's UI should be easily visible and navigable from a distance.
-Follow these tips to make them easier to see from a distance :
-</p>
-
-<ul>
- <li>Break text into small chunks that users can quickly scan.</li>
- <li>Use light text on a dark background. This style is easier to read on a TV.</li>
- <li>Avoid lightweight fonts or fonts that have both very narrow and very broad strokes. Use simple sans-serif
- fonts and use anti-aliasing to increase readability.</li>
- <li>Use Android's standard font sizes:
- <pre>
- <TextView
- android:id="@+id/atext"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceMedium"/>
- </pre></li>
- <li>Ensure that all your view widgets are large enough to be clearly visible to someone sitting 10 feet away
- from the screen (this distance is greater for very large screens). The best way to do this is to use
- layout-relative sizing rather than absolute sizing, and density-independent pixel units instead of absolute
- pixel units. For example, to set the width of a widget, use wrap_content instead of a pixel measurement,
- and to set the margin for a widget, use dip instead of px values.
- </li>
-</ul>
-<p>
-
-</p>
-
-<h2 id="DesignForLargeScreens">Design for High-Density Large Screens</h2>
-
-<p>
-The common HDTV display resolutions are 720p, 1080i, and 1080p. Design your UI for 1080p, and then
-allow the Android system to downscale your UI to 720p if necessary. In general, downscaling (removing pixels)
-does not degrade the UI (Notice that the converse is not true; you should avoid upscaling because it degrades
-UI quality).
-</p>
-
-<p>
-To get the best scaling results for images, provide them as <a href="{@docRoot}tools/help/draw9patch.html">
-9-patch image</a> elements if possible.
-If you provide low quality or small images in your layouts, they will appear pixelated, fuzzy, or grainy. This
-is not a good experience for the user. Instead, use high-quality images.
-</p>
-
-<p>
-For more information on optimizing apps for large screens see <a href="{@docRoot}training/multiscreen/index.html">
-Designing for multiple screens</a>.
-</p>
-
-<h2 id="HandleLargeBitmaps">Design to Handle Large Bitmaps</h2>
-
-<p>
-The Android system has a limited amount of memory, so downloading and storing high-resolution images can often
-cause out-of-memory errors in your app. To avoid this, follow these tips:
-</p>
-
-<ul>
- <li>Load images only when they're displayed on the screen. For example, when displaying multiple images in
- a {@link android.widget.GridView} or
- {@link android.widget.Gallery}, only load an image when
- {@link android.widget.Adapter#getView(int, View, ViewGroup) getView()}
- is called on the View's {@link android.widget.Adapter}.
- </li>
- <li>Call {@link android.graphics.Bitmap#recycle()} on
- {@link android.graphics.Bitmap} views that are no longer needed.
- </li>
- <li>Use {@link java.lang.ref.WeakReference} for storing references
- to {@link android.graphics.Bitmap} objects in an in-memory
- {@link java.util.Collection}.</li>
- <li>If you fetch images from the network, use {@link android.os.AsyncTask}
- to fetch them and store them on the SD card for faster access.
- Never do network transactions on the application's UI thread.
- </li>
- <li>Scale down really large images to a more appropriate size as you download them; otherwise, downloading the image
- itself may cause an "Out of Memory" exception. Here is sample code that scales down images while downloading:
-
- <pre>
- // Get the source image's dimensions
- BitmapFactory.Options options = new BitmapFactory.Options();
- // This does not download the actual image, just downloads headers.
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeFile(IMAGE_FILE_URL, options);
- // The actual width of the image.
- int srcWidth = options.outWidth;
- // The actual height of the image.
- int srcHeight = options.outHeight;
-
- // Only scale if the source is bigger than the width of the destination view.
- if(desiredWidth > srcWidth)
- desiredWidth = srcWidth;
-
- // Calculate the correct inSampleSize/scale value. This helps reduce memory use. It should be a power of 2.
- int inSampleSize = 1;
- while(srcWidth / 2 > desiredWidth){
- srcWidth /= 2;
- srcHeight /= 2;
- inSampleSize *= 2;
- }
-
- float desiredScale = (float) desiredWidth / srcWidth;
-
- // Decode with inSampleSize
- options.inJustDecodeBounds = false;
- options.inDither = false;
- options.inSampleSize = inSampleSize;
- options.inScaled = false;
- // Ensures the image stays as a 32-bit ARGB_8888 image.
- // This preserves image quality.
- options.inPreferredConfig = Bitmap.Config.ARGB_8888;
-
- Bitmap sampledSrcBitmap = BitmapFactory.decodeFile(IMAGE_FILE_URL, options);
-
- // Resize
- Matrix matrix = new Matrix();
- matrix.postScale(desiredScale, desiredScale);
- Bitmap scaledBitmap = Bitmap.createBitmap(sampledSrcBitmap, 0, 0,
- sampledSrcBitmap.getWidth(), sampledSrcBitmap.getHeight(), matrix, true);
- sampledSrcBitmap = null;
-
- // Save
- FileOutputStream out = new FileOutputStream(LOCAL_PATH_TO_STORE_IMAGE);
- scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
- scaledBitmap = null;
- </pre>
- </li> </ul>
\ No newline at end of file
diff --git a/docs/html/training/tv/optimizing-navigation-tv.jd b/docs/html/training/tv/optimizing-navigation-tv.jd
deleted file mode 100644
index bb78258..0000000
--- a/docs/html/training/tv/optimizing-navigation-tv.jd
+++ /dev/null
@@ -1,206 +0,0 @@
-page.title=Optimizing Navigation for TV
-parent.title=Designing for TV
-parent.link=index.html
-
-trainingnavtop=true
-previous.title=Optimizing Layouts for TV
-previous.link=optimizing-layouts-tv.html
-next.title=Handling Features Not Supported on TV
-next.link=unsupported-features-tv.html
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
- <li><a href="#HandleDpadNavigation">Handle D-pad Navigation</a></li>
- <li><a href="#HandleFocusSelection">Provide Clear Visual Indication for Focus and Selection</a></li>
- <li><a href="#DesignForEasyNavigation">Design for Easy Navigation</a></li>
-</ol>
-
-<h2>You should also read</h2>
-<ul>
- <li><a href="{@docRoot}training/design-navigation/index.html">Designing Effective Navigation</a></li>
-</ul>
-
-</div>
-</div>
-
-<p>
-An important aspect of the user experience when operating a TV is the direct human interface: a remote control.
-As you optimize your Android application for TVs, you should pay special attention to how the user actually navigates
-around your application when using a remote control instead of a touchscreen.
-</p>
-<p>
-This lesson shows you how to optimize navigation for TV by:
-</p>
-
-<ul>
- <li>Ensuring all layout controls are D-pad navigable.</li>
- <li>Providing highly obvious feedback for UI navigation.</li>
- <li>Placing layout controls for easy access.</li>
-</ul>
-
-<h2 id="HandleDpadNavigation">Handle D-pad Navigation</h2>
-
-<p>
-On a TV, users navigate with controls on a TV remote, using either a D-pad or arrow keys.
-This limits movement to up, down, left, and right.
-To build a great TV-optimized app, you must provide a navigation scheme in which the user can
-quickly learn how to navigate your app using the remote.
-</p>
-
-<p>
-When you design navigation for D-pad, follow these guidelines:
-</p>
-
-<ul>
- <li>Ensure that the D-pad can navigate to all the visible controls on the screen.</li>
- <li>For scrolling lists with focus, D-pad up/down keys scroll the list and Enter key selects an item in the list. Ensure that users can
- select an element in the list and that the list still scrolls when an element is selected.</li>
- <li>Ensure that movement between controls is straightforward and predictable.</li>
-</ul>
-
-<p>
-Android usually handles navigation order between layout elements automatically, so you don't need to do anything extra. If the screen layout
-makes navigation difficult, or if you want users to move through the layout in a specific way, you can set up explicit navigation for your
-controls.
-For example, for an {@code android.widget.EditText}, to define the next control to receive focus, use:
-<pre>
-<EditText android:id="@+id/LastNameField" android:nextFocusDown="@+id/FirstNameField"\>
-</pre>
-The following table lists all of the available navigation attributes:
-</p>
-
-<table>
-<tr>
-<th>Attribute</th>
-<th>Function</th>
-</tr>
-<tr>
-<td>{@link android.R.attr#nextFocusDown}</td>
-<td>Defines the next view to receive focus when the user navigates down.</td>
-</tr>
-<tr>
-<td>{@link android.R.attr#nextFocusLeft}</td>
-<td>Defines the next view to receive focus when the user navigates left.</td>
-</tr>
-<tr>
-<td>{@link android.R.attr#nextFocusRight}</td>
-<td>Defines the next view to receive focus when the user navigates right.</td>
-</tr>
-<tr>
-<td>{@link android.R.attr#nextFocusUp}</td>
-<td>Defines the next view to receive focus when the user navigates up.</td>
-</tr>
-</table>
-
-<p>
-To use one of these explicit navigation attributes, set the value to the ID (android:id value) of another widget in the layout. You should set
-up the navigation order as a loop, so that the last control directs focus back to the first one.
-</p>
-
-<p>
-Note: You should only use these attributes to modify the navigation order if the default order that the system applies does not work well.
-</p>
-
-<h2 id="HandleFocusSelection">Provide Clear Visual Indication for Focus and Selection</h2>
-
-<p>
-Use appropriate color highlights for all navigable and selectable elements in the UI. This makes it easy for users to know whether the control
-is currently focused or selected when they navigate with a D-pad. Also, use uniform highlight scheme across your application.
-</p>
-
-<p>
-Android provides <a href="{@docRoot}guide/topics/resources/drawable-resource.html#StateList">Drawable State List Resources</a> to implement highlights
-for selected and focused controls. For example:
-</p>
-
-res/drawable/button.xml:
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/button_pressed" /> <!-- pressed -->
- <item android:state_focused="true"
- android:drawable="@drawable/button_focused" /> <!-- focused -->
- <item android:state_hovered="true"
- android:drawable="@drawable/button_focused" /> <!-- hovered -->
- <item android:drawable="@drawable/button_normal" /> <!-- default -->
-</selector>
-</pre>
-
-<p>
-This layout XML applies the above state list drawable to a {@link android.widget.Button}:
-</p>
-<pre>
-<Button
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:background="@drawable/button" />
-</pre>
-
-<p>
-Provide sufficient padding within the focusable and selectable controls so that the highlights around them are clearly visible.
-</p>
-
-<h2 id="DesignForEasyNavigation">Design for Easy Navigation</h2>
-
-<p>
-Users should be able to navigate to any UI control with a couple of D-pad clicks. Navigation should be easy and intuitive to
-understand. For any non-intuitive actions, provide users with written help, using a dialog triggered by a help button or action bar icon.
-</p>
-
-<p>
-Predict the next screen that the user will want to navigate to and provide one click navigation to it. If the current screen UI is very sparse,
-consider making it a multi pane screen. Use fragments for making multi-pane screens. For example, consider the multi-pane UI below with continent names
-on the left and list of cool places in each continent on the right.
-</p>
-
-<img src="{@docRoot}images/training/cool-places.png" alt="" />
-
-<p>
-The above UI consists of three Fragments - <code>left_side_action_controls</code>, <code>continents</code> and
-<code>places</code> - as shown in its layout
-xml file below. Such multi-pane UIs make D-pad navigation easier and make good use of the horizontal screen space for
-TVs.
-</p>
-res/layout/cool_places.xml
-<pre>
-<LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- >
- <fragment
- android:id="@+id/left_side_action_controls"
- android:layout_width="0px"
- android:layout_height="match_parent"
- android:layout_marginLeft="10dip"
- android:layout_weight="0.2"/>
- <fragment
- android:id="@+id/continents"
- android:layout_width="0px"
- android:layout_height="match_parent"
- android:layout_marginLeft="10dip"
- android:layout_weight="0.2"/>
-
- <fragment
- android:id="@+id/places"
- android:layout_width="0px"
- android:layout_height="match_parent"
- android:layout_marginLeft="10dip"
- android:layout_weight="0.6"/>
-
-</LinearLayout>
-</pre>
-
-<p>
-Also, notice in the UI layout above action controls are on the left hand side of a vertically scrolling list to make
-them easily accessible using D-pad.
-In general, for layouts with horizontally scrolling components, place action controls on left or right hand side and
-vice versa for vertically scrolling components.
-</p>
-
diff --git a/docs/html/training/tv/unsupported-features-tv.jd b/docs/html/training/tv/unsupported-features-tv.jd
deleted file mode 100644
index a9f090b..0000000
--- a/docs/html/training/tv/unsupported-features-tv.jd
+++ /dev/null
@@ -1,157 +0,0 @@
-page.title=Handling Features Not Supported on TV
-parent.title=Designing for TV
-parent.link=index.html
-
-trainingnavtop=true
-previous.title=Optimizing Navigation for TV
-previous.link=optimizing-navigation-tv.html
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>This lesson teaches you to</h2>
-<ol>
- <li><a href="#WorkaroundUnsupportedFeatures">Work Around Features Not Supported on TV</a></li>
- <li><a href="#CheckAvailableFeatures">Check for Available Features at Runtime</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>
-TVs are much different from other Android-powered devices:
-</p>
-<ul>
- <li>They're not mobile.</li>
- <li>Out of habit, people use them for watching media with little or no interaction.</li>
- <li>People interact with them from a distance.</li>
-</ul>
-
-<p>
-Because TVs have a different purpose from other devices, they usually don't have hardware features
-that other Android-powered devices often have. For this reason, the Android system does not
-support the following features for a TV device:
-<table>
-<tr>
-<th>Hardware</th>
-<th>Android feature descriptor</th>
-</tr>
-<tr>
-<td>Camera</td>
-<td>android.hardware.camera</td>
-</tr>
-<tr>
-<td>GPS</td>
-<td>android.hardware.location.gps</td>
-</tr>
-<tr>
-<td>Microphone</td>
-<td>android.hardware.microphone</td>
-</tr>
-<tr>
-<td>Near Field Communications (NFC)</td>
-<td>android.hardware.nfc</td>
-</tr>
-<tr>
-<td>Telephony</td>
-<td>android.hardware.telephony</td>
-</tr>
-<tr>
-<td>Touchscreen</td>
-<td>android.hardware.touchscreen</td>
-</tr>
-</table>
-</p>
-
-<p>
-This lesson shows you how to work around features that are not available on TV by:
-<ul>
- <li>Providing work arounds for some non-supported features.</li>
- <li>Checking for available features at runtime and conditionally activating/deactivating certain code
- paths based on availability of those features.</li>
-</ul>
-</p>
-
-
-<h2 id="WorkaroundUnsupportedFeatures">Work Around Features Not Supported on TV</h2>
-
-<p>
-Android doesn't support touchscreen interaction for TV devices, most TVs don't have touch screens,
-and interacting with a TV using a touchscreen is not consistent with the 10 foot environment. For
-these reasons, users interact with Android-powered TVs using a remote. In consideration of this,
-ensure that every control in your app can be accessed with the D-pad. Refer back to the previous two lessons
-<a href="{@docRoot}training/tv/optimizing-layouts-tv.html">Optimizing Layouts for TV</a> and
-<a href="{@docRoot}training/tv/optimizing-navigation-tv.html">Optimize Navigation for TV</a> for
-more details
-on this topic. The Android system assumes that a device has a touchscreen, so if you want your application
-to run on a TV, you must <strong>explicitly</strong> disable the touchscreen requirement in your manifest file:
-<pre>
-<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
-</pre>
-</p>
-
-<p>
-Although a TV doesn't have a camera, you can still provide a photography-related application on a TV.
-For example, if you have an app that takes, views and edits photos, you can disable its picture-taking
-functionality for TVs and still allow users to view and even edit photos. The next section talks about how to
-deactivate or activate specific functions in the application based on runtime device type detection.
-</p>
-
-<p>
-Because TVs are stationary, indoor devices, they don't have built-in GPS. If your application uses location
-information, allow users to search for a location or use a "static" location provider to get
-a location from the zip code configured during the TV setup.
-<pre>
-LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
-Location location = locationManager.getLastKnownLocation("static");
-Geocoder geocoder = new Geocoder(this);
-Address address = null;
-
-try {
- address = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1).get(0);
- Log.d("Zip code", address.getPostalCode());
-
-} catch (IOException e) {
- Log.e(TAG, "Geocoder error", e);
-}
-</pre>
-</p>
-
-<p>
-TVs usually don't support microphones, but if you have an application that uses voice control,
-you can create a mobile device app that takes voice input and then acts as a remote control for a TV.
-</p>
-
-<h2 id="CheckAvailableFeatures">Check for Available Features at Runtime</h2>
-
-<p>
-To check if a feature is available at runtime, call
-{@link android.content.pm.PackageManager#hasSystemFeature(String)}.
- This method takes a single argument : a string corresponding to the
-feature you want to check. For example, to check for touchscreen, use
-{@link android.content.pm.PackageManager#hasSystemFeature(String)} with the argument
-{@link android.content.pm.PackageManager#FEATURE_TOUCHSCREEN}.
-</p>
-
-<p>
-The following code snippet demonstrates how to detect device type at runtime based on supported features:
-
-<pre>
-// Check if android.hardware.telephony feature is available.
-if (getPackageManager().hasSystemFeature("android.hardware.telephony")) {
- Log.d("Mobile Test", "Running on phone");
-// Check if android.hardware.touchscreen feature is available.
-} else if (getPackageManager().hasSystemFeature("android.hardware.touchscreen")) {
- Log.d("Tablet Test", "Running on devices that don't support telphony but have a touchscreen.");
-} else {
- Log.d("TV Test", "Running on a TV!");
-}
-</pre>
-</p>
-
-<p>
-This is just one example of using runtime checks to deactivate app functionality that depends on features
-that aren't available on TVs.
-</p>
\ No newline at end of file
diff --git a/docs/html/tv/images/hero.jpg b/docs/html/tv/images/hero.jpg
new file mode 100644
index 0000000..c42a436
--- /dev/null
+++ b/docs/html/tv/images/hero.jpg
Binary files differ
diff --git a/docs/html/tv/index.jd b/docs/html/tv/index.jd
new file mode 100644
index 0000000..e1cae8c
--- /dev/null
+++ b/docs/html/tv/index.jd
@@ -0,0 +1,262 @@
+page.title=Android TV
+page.viewport_width=970
+fullpage=true
+no_footer_links=true
+page.type=about
+
+
+@jd:body
+
+<style>
+.fullpage>#footer,
+#jd-content>.content-footer.wrap {
+ display:none;
+}
+</style>
+
+<style>
+#footer {
+ display: none;
+}
+.content-footer {
+ display: none;
+}
+</style>
+
+
+<div class="landing-body-content">
+ <div class="landing-hero-container">
+
+ <div class="landing-section tv-hero">
+ <div class="landing-hero-scrim"></div>
+ <div class="landing-hero-wrap">
+ <div class="vertical-center-outer">
+ <div class="vertical-center-inner">
+
+ <div class="col-10">
+ <div class="landing-section-header">
+ <div class="landing-h1 hero">Android TV</div>
+ <div class="landing-subhead hero">Your apps on the big screen</div>
+ <div class="landing-hero-description">
+ <p>Engage users from the comfort of their couches.
+ Put your app on TV and bring everyone into
+ the action.</p>
+ </div>
+
+ <div class="landing-body">
+ <a href="{@docRoot}preview/tv/index.html" class="landing-button landing-primary" style="margin-top: 40px;">
+ Get Started
+ </a>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div> <!-- end .wrap -->
+ <div class="landing-scroll-down-affordance">
+ <a class="landing-down-arrow" href="#reimagine-your-app">
+ <img src="{@docRoot}wear/images/carrot.png" alt="Scroll down to read more">
+ </a>
+ </div>
+ </div> <!-- end .landing-section .landing-hero -->
+ </div> <!-- end .landing-hero-container -->
+
+ <div class="landing-rest-of-page">
+
+ <div class="landing-section landing-gray-background" id="reimagine-your-app">
+ <div class="wrap">
+ <div class="landing-section-header">
+ <div class="landing-h1">Reimagine Your App</div>
+ <div class="landing-subhead">
+ Design your app to shine on the biggest screen in the house.
+ </div>
+ </div>
+
+
+ <div class="landing-body">
+ <div class="landing-breakout cols">
+
+ <div class="col-3-wide">
+ <img src="{@docRoot}tv/images/placeholder-square.png" alt="">
+
+ <p>Simple</p>
+ <p class="landing-small">
+ Smooth, fast interactions are key to a successful TV app. Keep navigation simple
+ and light. Bring your content forward to let users enjoy it with a minimum of
+ fuss.
+ </p>
+ <p class="landing-small">
+ <a href="{@docRoot}design/tv/index.html">Learn about TV design</a>
+ </p>
+ </div>
+
+ <div class="col-3-wide">
+ <img src="{@docRoot}tv/images/placeholder-square.png" alt="">
+
+ <p>Cinematic</p>
+ <p class="landing-small">
+ What would your app look like if it were a film? Use movement, animation and sound to make your app into an experience.
+ </p>
+ <p class="landing-small">
+ <a href="{@docRoot}design/tv/index.html">Learn about TV design</a>
+ </p>
+ </div>
+
+ <div class="col-3-wide">
+ <img src="{@docRoot}tv/images/placeholder-square.png" alt="">
+
+ <p>Beautiful</p>
+ <p class="landing-small">
+ Apps on TV should be a pleasure to look at, as well as enjoyable to use. Use
+ made-for-TV styles to make your app familiar and fun.
+ </p>
+ <p class="landing-small">
+ <a href="{@docRoot}design/tv/index.html">Learn about design for TV</a>
+ </p>
+ </div>
+ </div>
+
+ </div>
+ </div> <!-- end .wrap -->
+ </div> <!-- end .landing-section -->
+
+ <div class="landing-section" style="background-color:#f5f5f5">
+ <div class="wrap">
+ <div class="landing-section-header">
+ <div class="landing-h1">Build to Entertain</div>
+ <div class="landing-subhead">
+ Android TV let's you engage your users in a new, shared environment.<br>
+ Find out how to get your app ready for it's big screen debut.
+ </div>
+ </div>
+
+
+ <div class="landing-body">
+ <div class="landing-breakout cols">
+
+ <div class="col-3-wide">
+ <img src="{@docRoot}tv/images/placeholder-square.png" alt="">
+
+ <p>Made for TV</p>
+ <p class="landing-small">
+ Take advantage of pre-built fragments for browsing and interacting with media
+ catalogs.
+ </p>
+ <p class="landing-small">
+ <a href="{@docRoot}design/tv/index.html">Learn pre-built fragments</a>
+ </p>
+ </div>
+
+ <div class="col-3-wide">
+ <img src="{@docRoot}tv/images/placeholder-square.png" alt="">
+
+ <p>Get Found</p>
+ <p class="landing-small">
+ Give your content the attention it deserves by including it in Android TV's global
+ search results.
+ </p>
+ <p class="landing-small">
+ <a href="{@docRoot}design/tv/index.html">Learn about TV design</a>
+ </p>
+ </div>
+
+ <div class="col-3-wide">
+ <img src="{@docRoot}tv/images/placeholder-square.png" alt="">
+
+ <p>Recommend</p>
+ <p class="landing-small">
+ Suggest content from your app to keep your users coming back.
+ </p>
+ <p class="landing-small">
+ <a href="{@docRoot}design/tv/index.html">Learn about design for TV</a>
+ </p>
+ </div>
+
+ </div>
+
+ </div>
+ </div> <!-- end .wrap -->
+ </div> <!-- end .landing-section -->
+
+ <div class="landing-section landing-red-background">
+ <div class="wrap">
+ <div class="landing-section-header">
+ <div class="landing-h1 landing-align-left">Get Started with Android TV</div>
+ <div class="landing-body">
+ <p>You can begin building apps right away using these developer resources.</p>
+ </div>
+ </div>
+
+ <div class="landing-body">
+ <div class="landing-breakout cols">
+ <div class="col-8">
+ <p>Preview SDK</p>
+ <p>
+ Get started building for Android TV using the Android L-preview SDK. The preview
+ SDK includes the Android TV emulator so you can start building your TV app right
+ away.
+ </p>
+
+ </div>
+
+ <div class="col-8">
+ <p>ADT-1 Developer Kit</p>
+ <p>
+ While supplies last, developers can request an ADT-1 Developer Kit, a compact and
+ powerful streaming media player and gamepad, ideal for developing apps for Android
+ TV.
+ </p>
+
+ </div>
+
+ </div>
+ </div>
+
+ <div class="landing-body">
+ <div class="landing-breakout cols">
+
+ <div class="col-8">
+ <a href="{@docRoot}preview/download.html" class="landing-button landing-secondary">
+ Download the Preview SDK
+ </a>
+ </div>
+
+ <div class="col-8">
+ <a href="{@docRoot}tv/adt-1/request.html" class="landing-button landing-secondary">
+ Request ADT-1 Developer Kit
+ </a>
+ </div>
+ </div>
+
+ </div> <!-- end .wrap -->
+ </div> <!-- end .landing-section -->
+
+ </div> <!-- end .landing-rest-of-page -->
+
+
+ <div class="content-footer wrap" itemscope="" itemtype="http://schema.org/SiteNavigationElement">
+ <div class="layout-content-col col-16" style="padding-top:4px">
+ <style>#___plusone_0 {float:right !important;}</style>
+ <div class="g-plusone" data-size="medium"></div>
+ </div>
+ </div>
+ <div id="footer" class="wrap" style="width:940px;position:relative;top:-35px;z-index:-1">
+ <div id="copyright">
+ Except as noted, this content is
+ licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
+ Creative Commons Attribution 2.5</a>. For details and
+ restrictions, see the <a href="/license.html">Content
+ License</a>.
+ </div>
+ </div>
+
+
+ </div> <!-- end landing-body-content -->
+
+ <script>
+ $("a.landing-down-arrow").on("click", function(e) {
+ $("body").animate({
+ scrollTop: $(".wear-hero").height() + 76
+ }, 1000, "easeOutQuint");
+ e.preventDefault();
+ });
+ </script>
diff --git a/docs/html/wear/css/wear.css b/docs/html/wear/css/wear.css
deleted file mode 100644
index fe9eef2..0000000
--- a/docs/html/wear/css/wear.css
+++ /dev/null
@@ -1,447 +0,0 @@
-/**
- * UTILITIES
- */
-
-
-.border-box {
- box-sizing: border-box;
-}
-
-.vertical-center-outer {
- display: table;
- height: 100%;
- width: 100%;
-}
-
-.vertical-center-inner {
- display: table-cell;
- vertical-align: middle;
-}
-
-/**
- * TYPE STYLES
- */
-
-.wear-h1 {
- font-weight: 300;
- font-size: 60px;
- line-height: 78px;
- text-align: center;
- letter-spacing: -1px;
-}
-
-.wear-pre-h1 {
- font-weight: 400;
- font-size: 28px;
- color: #93B73F;
- line-height: 36px;
- text-align: center;
- letter-spacing: -1px;
- text-transform: uppercase;
-
-}
-
-.wear-h1.hero {
- text-align: left;
-}
-
-.wear-h2 {
- font-weight: 300;
- font-size: 42px;
- line-height: 64px;
- text-align: center;
-}
-
-
-.wear-subhead {
- color: #999999;
- font-size: 20px;
- line-height: 28px;
- text-align: center;
-}
-.wear-subhead.hero {
- text-align: left;
- color: white;
-}
-
-.wear-hero-description {
- text-align: left;
- margin: 1em 0;
-}
-
-.wear-hero-description p {
- font-weight: 300;
- margin: 0;
- font-size: 18px;
- line-height: 24px;
-}
-
-.wear-body .wear-small {
- font-size: 14px;
- line-height: 19px;
-}
-
-.wear-body.wear-align-center {
- text-align: center;
-}
-
-.wear-align-left {
- text-align: left;
-}
-
-/**
- * LAYOUT
- */
-
-#body-content,
-.fullpage,
-#jd-content,
-.jd-descr,
-.wear-body-content {
- height: 100%;
-}
-
-.wear-section {
- padding: 80px 10px 80px;
- width: 100%;
- margin-left: -10px;
- text-rendering: optimizeLegibility;
-}
-
-#extending-android-to-wearables {
- padding-top: 30px;
-}
-
-.wear-short-section {
- padding: 40px 10px 28px;
-}
-
-.wear-gray-background {
- background-color: #e9e9e9;
-}
-
-.wear-white-background {
- background-color: white;
-}
-
-.wear-red-background {
- color: white;
- background-color: hsl(8, 70%, 54%);
-}
-
-.wear-subhead-red {
- color: hsl(8, 71%, 84%);
- text-align: left;
-}
-
-.wear-subhead-red p {
- margin-top: 20px;
-}
-
-.wear-hero-container {
- height: 100%;
-}
-
-.wear-hero {
- height: calc(100% - 70px);
- min-height: 504px;
- margin-top: 0;
- padding-top: 0;
- padding-bottom: 0;
- background-image: url(/wear/images/hero.jpg);
- background-size: cover;
- background-position: right center;
- color: white;
- position: relative;
- overflow: hidden;
-}
-
-.wear-hero-scrim {
- background: black;
- opacity: .2;
- position: absolute;
- width: 100%;
- height: 100%;
- margin-left: -10px;
-}
-
-.wear-hero-wrap {
- margin: 0 auto;
- width: 940px;
- clear: both;
- height: 100%;
- position: relative;
-}
-
-.wear-section-header {
- margin-bottom: 40px;
-}
-
-.wear-hero-wrap .wear-section-header {
- margin-bottom: 16px;
-}
-
-.wear-body {
- font-size: 18px;
- line-height: 24px;
-}
-
-.wear-button {
- white-space: nowrap;
- display: inline-block;
- padding: 16px 32px;
- font-size: 18px;
- font-weight: 500;
- line-height: 24px;
- cursor: pointer;
- color: white;
- -webkit-user-select: none;
- -moz-user-select: none;
- -o-user-select: none;
- user-select: none;
- -webkit-transition: .2s background-color ease-in-out;
- -moz-transition: .2s background-color ease-in-out;
- -o-transition: .2s background-color ease-in-out;
- transition: .2s background-color ease-in-out;
-}
-
-.wear-primary {
- background-color: hsl(8, 70%, 54%); /* #dc4b35 */
- color: #f8f8f8;
-}
-
-.wear-button.wear-primary:hover {
- background-color: hsl(8, 70%, 44%); /* #bf3722 */
-}
-
-.wear-button.wear-primary:active {
- background-color: hsl(8, 70%, 36%); /* # */
-}
-
-.wear-button.wear-secondary {
- background-color: hsl(8, 70%, 44%);
-}
-
-.wear-button.wear-secondary:hover {
- background-color: hsl(8, 70%, 36%);
-}
-
-.wear-button.wear-secondary:active {
- background-color: hsl(8, 70%, 30%);
-}
-
-a.wear-button,
-a.wear-button:hover,
-a.wear-button:visited {
- color: white !important;
-}
-
-.wear-video-link {
- white-space: nowrap;
- display: inline-block;
- padding: 16px 32px 16px 82px;
- font-size: 18px;
- font-weight: 400;
- line-height: 24px;
- cursor: pointer;
- color: hsla(0, 0%, 100%, .8);
- -webkit-user-select: none;
- -moz-user-select: none;
- -o-user-select: none;
- user-select: none;
- -webkit-transition: .2s color ease-in-out;
- -moz-transition: .2s color ease-in-out;
- -o-transition: .2s color ease-in-out;
- transition: .2s color ease-in-out;
-}
-
-.wear-video-link:before {
- height: 64px;
- width: 64px;
- display: inline-block;
- background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAFuklEQVR42u2dXWgcVRSAV9LWtBBTTZVWUhNqEQtq1QeroDRKFRFsROqTYPuo+JCiIoJKFC0USqlUfCiowRcfrBgVUUElefAPkW5T8aeaGn9aRbFsjP0x2cx8PuRMvFxmdjeb2Z17Z8+B85DsZPbO+eaec3/OPSkABdXsVI2gABSAqgJQAKoKQAGoKgAFoKoAFICqAlAAqgpAAai6DqDRAiwDeoFtwB7gPaAInABKwKToCWAMeB/YDdwJrAWWNLh9+QMAXABsBQ4A3wFTwAxQBmaBAAhjNJDPy3L938BXwAvArUCHAkh+kCXAVcA+YBw4bRg7MngtkgTlDPA98CywHmhTAP8/xCbgVeAvMZZpwDQllN7xB/AysKGlAQAXAvuBkzW85UVgCBgENlfQQbmuWAXELPAnsAvoaikAQBtwh/j3coLhS2LIfqCzzu/plL8fkvvFgZiR4L2lHrfkHQBgpQTFUwmGnwC212v0KjC2y/3jQPwDPA+05xYAcBHwubx1YZzhC02QBBBRbxgBzssdAOBy4JgRZE0ZTPuNr7FHDCbEhqNAd24AAN0yUbID7QSwsZChABut3hANXY8Bq70HIMb/Ocb4w81+66v0hmGrN0QQ1ngLQJYRvpWHMWWo4KDIaMnuCcVKgdlZAGL8t2J8vpPGrwChDLyWBMFlAA8D0z4ZvwKEs8D93gCQEc9Jy/jFgkdizaRDGUSs8wXAu1bQLQE9ngHosWbPAXDQeQAypT9rBd3+gociyxi2K9riLABZUj5iuZ6RgsciM2OzFxw2A7JrAO6VwGtKTwpG+Anoy9AVmb3gDHCPcwCAFcChRox6jPu9CazMeFQUAKNRL3AJwE2yopjq228BQPZ/d2bcCyaBTa4BeNGa8Q6naIA4GQWubiKEYWvBbp8zAGQt5VfL/fQ3GEAkTzXDLVkjokA2k5a7AuA2GaLNj/tTfvhq0pQgbcwLQtlQusYVALtlzSR191MjADNI9zbJDZWBR10BMGr5/4GMADQ0SAMDlht62xUAxy0AmzMEEMnhtIO0ZF2YAH5wITd0hQw/5wE04M1bjDyXZpC2hqMlYGnWAHqBf40APOEYgChI35VSWyasWfGqrAH0WVkOIw4CSC1IG2tDoSy7XJE1gPs8ArDoIG0BmJGk30wBDHgGYFFBOgbAtqwB7GxxAHerC8rOBU0Dt2gQzjYIb8gawDor+6HVhqFdrkzEwhabiAVOTMSkUb+06FLEUVfWgj5q0cW4g64AeNo66ZLlcnTDNmesBN4y8KArAG6QU42ttCEzBVzpCoAO4EfLDeV5SzIEvgHaXdqUP2BlQud1Ux55zj2uZUX02cPRnKalRLmu17qYmPWF5YbymJgVAh8Ay5wCII3ZEZOYm6fURGT2u9X43Mnk3CDHybmfmRVYXExPv9nKEcpLejqSC3SjdY2TBzTesHqB7wc0onTEV2KucxLApXKkJy9HlAI5anuJFwCkYQ/EuCJfD+mdBnYkXOssgHY53un7MdVZ4CVgqVcADAhjMafkfTioHc14P04yvvMApIEXy5F/+7S8y6UKolPyR4BVVf7Wi2IdawwIPhTrmAW+rmZ8bwBIQ7vloXwoVzNWS6UUrwAYy9YfOlqwKZDkgneA5Qu4l3cly84F9sqGhislywLmaozuYoGFXr0DII1ukxP1hxJ6QzR7HqLxRfumZaRzXZ3f4XXZyi7gCeB3kqsnzs+kSb9s5XHgMeD8RTxDLgq3rmeuYuFvNYCoR8wqujNi+L3UWBcu9wAMt3QZ8LiMlk5RuU50teq6kcEDgTolveIRYHUQBOek1O5cFu/ukLz7/ZJgNSm+OirebWpgaPS7slxfAr4EngGuX8jopqUBxGzyrAVuB54EXgc+lV4yLhO8cfn5E+ZqUD8kBu9sQvv0Hzj4rmoEBaAAVBWAAlBVAApAVQEoAFUFoABUFYACUFUACkC1CfofXVRJocowZVYAAAAASUVORK5CYII=);
- background-size: contain;
- position: absolute;
- content: "";
- opacity: .7;
- margin-top: -19px;
- margin-left: -64px;
- -webkit-transition: .2s opacity ease-in-out;
- -moz-transition: .2s opacity ease-in-out;
- -o-transition: .2s opacity ease-in-out;
- transition: .2s opacity ease-in-out;
-}
-
-.wear-video-link:hover {
- color: hsla(0, 0%, 100%, 1);
-}
-
-.wear-video-link:hover:before {
- opacity: 1;
-}
-
-.wear-social-image {
- float: left;
- margin-right: 14px;
- height: 64px;
- width: 64px;
-}
-
-.wear-social-copy {
- padding-left: 78px;
-}
-
-.wear-scroll-down-affordance {
- position: absolute;
- bottom: 0;
- width: 100%;
- text-align: center;
- z-index: 10;
-}
-
-.wear-down-arrow {
- padding: 24px;
- display: inline-block;
- opacity: .5;
- -webkit-transition: .2s opacity ease-in-out;
- -moz-transition: .2s opacity ease-in-out;
- -o-transition: .2s opacity ease-in-out;
- transition: .2s opacity ease-in-out;
-
- -webkit-animation-name: pulse-opacity;
- -webkit-animation-duration: 4s;
-}
-
-.wear-down-arrow:hover {
- opacity: 1;
-}
-
-.wear-down-arrow img {
- height: 28px;
- width: 28px;
- margin: 0 auto;
- display: block;
-}
-
-.wear-divider {
- display: inline-block;
- height: 2px;
- background-color: white;
- position: relative;
- margin: 10px 0;
-}
-
-/* 3 CLOLUMN LAYOUT */
-
-.wear-breakout {
- margin-top: 40px;
- margin-bottom: 40px;
-}
-
-.wear-breakout img {
- margin-bottom: 20px;
-}
-
-.wear-partners img {
- margin-bottom: 20px;
-}
-
-.wear-breakout p {
- padding: 0 23px;
-}
-
-.wear-inset-video-container {
- position: relative;
-}
-
-.wear-inset-video-container img.gif {
- max-width: 222px;
- position: absolute;
- top: 40px;
- left: 40px;
-}
-
-img.wear-bezel-only {
- height:302px;
- width:302px;
-}
-
-.wear-breakout.wear-partners img {
- margin-bottom: 20px;
-}
-
-.col-3-wide {
- display: inline;
- float: left;
- margin-left: 10px;
- margin-right: 10px;
-}
-
-.col-3-wide {
- width: 302px;
-}
-
-/**
- * ANIMATION
- */
-
-@-webkit-keyframes pulse-opacity {
- 0% {
- opacity: .5;
- }
- 20% {
- opacity: .5;
- }
- 40% {
- opacity: 1;
- }
- 60% {
- opacity: .5;
- }
- 80% {
- opacity: 1;
- }
- 100% {
- opacity: .5;
- }
-}
-
-
-
-/**
- * VIDEO
- */
-
-#video-container {
- display:none;
- position:fixed;
- top:0;
- left:-10px;
- width:102%;
- height:100%;
- background-color:rgba(0,0,0,0.7);
- z-index:99;
-}
-
-#video-frame {
- width:940px;
- height:526.4px;
- margin:80px auto 0;
- display:none;
-}
-
-.video-close {
-cursor: pointer;
-position: relative;
-left: 940px;
-top: 0;
-pointer-events: all;
-}
-
-#icon-video-close {
-background-image: url("../images/close.png");
-background-position: 0 0;
-height: 36px;
-width: 36px;
-display:block;
-}
diff --git a/docs/html/wear/images/hero.jpg b/docs/html/wear/images/hero.jpg
index 40cc03c..7850a81 100644
--- a/docs/html/wear/images/hero.jpg
+++ b/docs/html/wear/images/hero.jpg
Binary files differ
diff --git a/docs/html/wear/images/kitchen_still.jpg b/docs/html/wear/images/kitchen_still.jpg
deleted file mode 100644
index 4afe359..0000000
--- a/docs/html/wear/images/kitchen_still.jpg
+++ /dev/null
Binary files differ
diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd
index 659e9f2..59d5506 100644
--- a/docs/html/wear/index.jd
+++ b/docs/html/wear/index.jd
@@ -2,7 +2,7 @@
page.viewport_width=970
fullpage=true
no_footer_links=true
-page.customHeadTag=<link rel="stylesheet" type="text/css" href="/wear/css/wear.css">
+page.type=about
@jd:body
@@ -14,8 +14,6 @@
</style>
-
-
<div id="video-container">
<div id="video-frame">
<div class="video-close">
@@ -23,28 +21,28 @@
</div>
<script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
<div id="ytapiplayer">
- <a href="http://www.youtube.com/watch?v=0xQ3y902DEQ"><img width=940
- src="https://i1.ytimg.com/vi/0xQ3y902DEQ/maxresdefault.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
+ <a href="http://www.youtube.com/watch?v=0xQ3y902DEQ"><img width="940" src="https://i1.ytimg.com/vi/0xQ3y902DEQ/maxresdefault.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
</div>
</div>
</div>
-<div class="wear-body-content">
- <div class="wear-hero-container">
- <div class="wear-section wear-hero">
- <div class="wear-hero-scrim"></div>
- <div class="wear-hero-wrap">
+<div class="landing-body-content">
+ <div class="landing-hero-container">
+ <div class="landing-section wear-hero">
+ <div class="landing-hero-scrim"></div>
+ <div class="landing-hero-wrap">
<div class="vertical-center-outer">
<div class="vertical-center-inner">
<div class="col-10">
- <div class="wear-section-header">
- <div class="wear-h1 hero">Android Wear</div>
- <div class="wear-subhead hero">Information that moves with you</div>
+ <div class="landing-section-header">
+ <div class="landing-h1 hero">Android Wear</div>
+ <div class="landing-subhead hero">Information that moves with you</div>
</div>
- <div class="wear-hero-description">
+ <div class="landing-hero-description">
+
<p>Small, powerful devices, worn on the body.
Useful information when you need it most.
Intelligent answers to spoken questions.
@@ -52,318 +50,208 @@
Your key to a multiscreen world.</p>
</div>
- <div class="wear-body">
- <a href="/wear/preview/start.html" class="wear-button wear-primary" style="margin-top: 40px;">
- Get the Developer Preview
+ <div class="landing-body">
+ <a href="{@docRoot}training/building-wearables.html" class="landing-button landing-primary" style="margin-top: 40px;">
+ Get Started
</a>
- <a id="watchVideo" href="https://youtube.googleapis.com/v/0xQ3y902DEQ">
- <div class="wear-video-link">Watch the video</div>
- </a>
-<script>
-$("#watchVideo").on("click", function(e) {
- $("#video-container").fadeIn(400, function(){$("#video-frame").show()});
-
- var params = { allowScriptAccess: "always"};
- var atts = { id: "ytapiplayer" };
- swfobject.embedSWF("//www.youtube.com/v/0xQ3y902DEQ?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1;autoplay=1",
- "ytapiplayer", "940", "526.4", "8", null, null, params, atts);
-
- e.preventDefault();
-});
-$("#icon-video-close").on("click", function() {
- ytplayer = document.getElementById("ytapiplayer");
- try {
- ytplayer.stopVideo();
- $(ytplayer).hide();
- $("#video-container").fadeOut(400);
- } catch(e) {
- console.log('Video not available');
- $("#video-container").fadeOut(400);
- }
-});
-</script>
</div>
</div>
</div>
</div>
</div> <!-- end .wrap -->
- <div class="wear-scroll-down-affordance">
- <a class="wear-down-arrow" href="#extending-android-to-wearables">
- <img src="/wear/images/carrot.png" alt="Scroll down to read more">
+ <div class="landing-scroll-down-affordance">
+ <a class="landing-down-arrow" href="#extending-android-to-wearables">
+ <img src="{@docRoot}wear/images/carrot.png" alt="Scroll down to read more">
</a>
</div>
- </div> <!-- end .wear-section .wear-hero -->
- </div> <!-- end .wear-hero-container -->
+ </div> <!-- end .landing-section .landing-hero -->
+ </div> <!-- end .landing-hero-container -->
- <div class="wear-rest-of-page">
- <div class="wear-section" id="extending-android-to-wearables">
+ <div class="landing-rest-of-page">
+ <div class="landing-section" id="extending-android-to-wearables">
<div class="wrap">
- <div class="wear-section-header">
- <div class="wear-h1">Extending Android to Wearables</div>
- <div class="wear-subhead">
- Android Wear extends the Android platform to a new generation of wearable devices. <br>
- The user experience is designed specifically for wearables.
+ <div class="landing-section-header">
+ <div class="landing-h1">Extending Android to Wearables</div>
+ <div class="landing-subhead">
+ Android Wear extends the Android platform to a new generation of devices, <br>
+ with a user experience that's designed specifically for wearables.
+
</div>
</div>
- <div class="wear-body">
- <div class="wear-breakout cols">
+ <div class="landing-body">
+ <div class="landing-breakout cols">
<div class="col-3-wide">
- <div class="wear-inset-video-container">
- <img class="wear-bezel-only" src="/wear/images/screens/bezel.png" alt="">
- <img class="gif" src="/wear/images/screens/reservation_animated.gif">
+ <div class="landing-inset-video-container">
+ <img class="landing-bezel-only" src="{@docRoot}wear/images/screens/bezel.png" alt="">
+ <img class="gif" src="{@docRoot}wear/images/screens/reservation_animated.gif">
</div>
- <p class="wear-small">
+ <p class="landing-small">
Say “Ok Google” to ask questions and get stuff done.
</p>
</div>
<div class="col-3-wide">
- <img src="/wear/images/screens/circle_message2.png" itemprop="image" alt="" >
- <p class="wear-small">
- Get glanceable, actionable information at just the right time throughout the day.
+ <img src="{@docRoot}wear/images/screens/circle_message2.png" itemprop="image" alt="">
+ <p class="landing-small">
+ Get glanceable, actionable information at just the right time with notifications
+ that are synced from your handheld device.
+
</p>
</div>
<div class="col-3-wide">
- <img src="/wear/images/screens/fitness-24.png" alt="">
- <p class="wear-small">
- A wide range of sensors is available to your applications, from accelerometers to heart rate monitors.
+ <img src="{@docRoot}wear/images/screens/fitness-24.png" alt="">
+ <p class="landing-small">
+ Design apps that can access a wide range of sensors and other hardware
+ directly on the wearable.
+
</p>
</div>
</div>
<p>
- The Android Wear Developer Preview lets you create wearable experiences for your existing Android apps and see how they will appear on square and round Android wearables.
- </p>
-
- <p>
- Later this year, we’ll be launching the Android Wear SDK, enabling even more customized experiences.
- </p>
- </div>
- </div> <!-- end .wrap -->
- </div> <!-- end .wear-section -->
-
- <div class="wear-section wear-gray-background">
- <div class="wrap">
- <div class="wear-section-header">
- <div class="wear-h1">Developer Preview</div>
- <div class="wear-subhead">
- Your app’s notifications will already appear on Android wearables. <br>
- With the new Android Wear APIs you can customize and extend those notifications.
- </div>
- </div>
-
-
- <div class="wear-body">
- <div class="wear-breakout cols">
- <div class="col-3-wide">
- <img src="images/screens/14_circle_voicereply.png" alt="">
- <p>Receive Voice Replies</p>
- <p class="wear-small">
- Add actions to your notifications to allow users to reply by voice or touch. The system delivers the text to your app on the phone.
- </p>
- <p class="wear-small">
- <a href="/wear/notifications/remote-input.html">Learn about input actions</a>
- </p>
- </div>
- <div class="col-3-wide">
-
-
- <div class="wear-inset-video-container">
- <img class="wear-bezel-only" src="/wear/images/screens/bezel.png" alt="">
- <img class="gif" src="/wear/images/screens/pages_animated.gif">
- </div>
-
- <p>Add Notification Pages</p>
- <p class="wear-small">
- Add additional pages to your notification that are visible on the wearable device to provide detailed information on the wrist.
- </p>
- <p class="wear-small">
- <a href="/wear/notifications/pages.html">Learn about pages</a>
- </p>
- </div>
- <div class="col-3-wide">
- <img src="images/screens/11_stack_B.png" alt="">
- <p>Stack Multiple Notifications</p>
- <p class="wear-small">
- Your app should consolidate similar notifications. On a wearable, you can stack them together so the details for each are immediately available.
- </p>
- <p class="wear-small">
- <a href="/wear/notifications/stacks.html">Learn about stacks</a>
- </p>
- </div>
- </div>
-
- <p>
- You can also trigger your notifications contextually using existing Android APIs. For example, use <a href="{@docRoot}training/location/geofencing.html">geofences</a> to provide glanceable information to your users when they are at home, or use the <a href="{@docRoot}training/location/activity-recognition.html">activity detection APIs</a> to send messages to your users’ wrists while they are bicycling.
- </p>
-
- <p>See the <a href="{@docRoot}wear/design/index.html">Android Wear Developer Preview Design Principles</a> for more suggestions on creating great wearable experiences.</p>
+ Before you start building, check out the
+ <a href="{@docRoot}design/wear/index.html">Android Wear Design Principles</a>
+ to understand how to create great experiences for this exciting, new form factor.</p>
</div>
</div> <!-- end .wrap -->
- </div> <!-- end .wear-section -->
+ </div> <!-- end .landing-section -->
- <div class="wear-section" style="background-color:#f5f5f5">
+ <div class="landing-section landing-gray-background">
<div class="wrap">
- <div class="wear-section-header">
- <div class="wear-pre-h1">Coming soon</div>
- <div class="wear-h1">The Android Wear SDK</div>
- <div class="wear-subhead">
- The Developer Preview is just the beginning for Android Wear.
+ <div class="landing-section-header">
+ <div class="landing-h1">Developing for Android Wear</div>
+ <div class="landing-subhead">
+ The Android Wear APIs are delivered in the Android v4 support library and Google Play services.
+ This lets Android handhelds, old and new, communicate with Android wearables.
</div>
</div>
- <div class="wear-body">
- <p>
- In the coming months we’ll be launching new APIs and features for Android wearables to create even more unique experiences for the wrist:
- </p>
-
- <div class="wear-breakout cols">
+ <div class="landing-body">
+ <div class="landing-breakout cols">
<div class="col-4">
- <img src="/wear/images/features/ts1.png" alt="">
- <p>Build Custom UI</p>
- <p class="wear-small">
- Create custom card layouts and run activities directly on wearables.
+ <img src="{@docRoot}wear/images/features/ts2.png" alt="">
+ <p>Synced Notifications</p>
+ <p class="landing-small">
+ Notifications on handhelds can automatically sync to wearables, so design them
+ with both devices in mind.
+ </p>
+ <p class="landing-small">
+ <a href="{@docRoot}training/wearables/notifications/index.html">Build notifications</a>
</p>
</div>
<div class="col-4">
- <img src="/wear/images/features/ts2.png" alt="">
+ <img src="{@docRoot}wear/images/features/ts1.png" alt="">
+ <p>Wearable Apps</p>
+ <p class="landing-small">
+ Create custom experiences with activities, services, sensors, and much
+ more with the Android SDK.
+ </p>
+ <p class="landing-small">
+ <a href="{@docRoot}training/wearables/apps/index.html">Create wearable apps</a>
+
+ </p>
+ </div>
+ <div class="col-4">
+ <img src="{@docRoot}wear/images/features/ts2.png" alt="">
<p>Send Data</p>
- <p class="wear-small">
- Send data and actions between a phone and a wearable with data replication APIs and RPCs.
+ <p class="landing-small">
+ Send data and actions between handhelds and wearables with
+ data replication APIs and RPCs.
+ </p>
+ <p class="landing-small">
+ <a href="{@docRoot}training/wearables/data-layer/index.html">Work with the Data Layer</a>
+
</p>
</div>
<div class="col-4">
- <img src="/wear/images/features/ts3.png" alt="">
- <p>Control Sensors</p>
- <p class="wear-small">
- Gather sensor data and display it in real-time on Android wearables.
- </p>
- </div>
- <div class="col-4">
- <img src="/wear/images/features/ts4.png" alt="">
+ <img src="{@docRoot}wear/images/features/ts4.png" alt="">
<p>Voice Actions</p>
- <p class="wear-small">
- Register your app to handle voice actions, like "Ok Google, take a note."
+ <p class="landing-small">
+ Register your app to handle voice actions, like "Ok Google, take a note,"
+ for a hands-free experience.
+ </p>
+ <p class="landing-small">
+ <a href="{@docRoot}training/wearables/apps/voice-actions.html">Integrate voice actions</a>
</p>
</div>
</div>
-
</div>
</div> <!-- end .wrap -->
- </div> <!-- end .wear-section -->
+ </div> <!-- end .landing-section -->
- <div class="wear-section wear-white-background">
+ <div class="landing-section landing-red-background">
<div class="wrap">
- <div class="wear-section-header">
- <div class="wear-h2">Building an Ecosystem</div>
- <div class="wear-body wear-align-center">
- <p class="wear-small">
- We’re working with several partners to bring you watches powered by Android Wear later this year!
- </p>
- </div>
- </div>
+ <div class="landing-section-header">
+ <div class="landing-h1 landing-align-left">Get Started with Android Wear</div>
- <div class="wear-partners cols">
- <div class="col-4">
- <img src="/wear/images/partners/asus.png" alt="Asus">
- </div>
- <div class="col-4">
- <img src="/wear/images/partners/broadcom.png" alt="Broadcom">
- </div>
- <div class="col-4">
- <img src="/wear/images/partners/fossil.png" alt="Fossil">
- </div>
- <div class="col-4">
- <img src="/wear/images/partners/htc.png" alt="HTC">
- </div>
- <div class="col-4">
- <img src="/wear/images/partners/intel.png" alt="Intel">
- </div>
- <div class="col-4">
- <img src="/wear/images/partners/lg.png" alt="LG">
- </div>
- <div class="col-4">
- <img src="/wear/images/partners/mediatek.png" alt="Mediatek">
- </div>
- <div class="col-4">
- <img src="/wear/images/partners/mips.png" alt="MIPS">
- </div>
- <div class="col-4">
- <img src="/wear/images/partners/motorola.png" alt="Motorola">
- </div>
- <div class="col-4">
- <img src="/wear/images/partners/qualcomm.png" alt="Qualcomm">
- </div>
- <div class="col-4">
- <img src="/wear/images/partners/samsung.png" alt="Samsung">
+ <div class="landing-subhead landing-subhead-red">
+ <p>
+ Set up your development environment and start working with the APIs.
+ We’re excited about the experiences you'll create and can't
+ wait to see what you do next.</p>
</div>
</div>
- </div> <!-- end .wrap -->
- </div> <!-- end .wear-section -->
-
- <div class="wear-section wear-red-background">
- <div class="wrap">
- <div class="wear-section-header">
- <div class="wear-h1 wear-align-left">Start working with Android Wear</div>
- <div class="wear-subhead wear-subhead-red">
- <p>
- Your app’s notifications will already appear on Android wearables. <br>
- With the new Android Wear APIs, you can customize and extend those notifications.
- </p>
- <p>
- We’re excited about wearables and the experiences developers can create with them. <br>
- We can’t wait to see what you do next.</p>
- </div>
- </div>
- <div class="wear-body">
- <a href="/wear/preview/start.html" class="wear-button wear-secondary" style="margin-top: 20px;">
- Get the Developer Preview
+ <div class="landing-body">
+ <a href="{@docRoot}training/building-wearables.html" class="landing-button landing-secondary" style="margin-top: 20px;">
+ Get Started
</a>
</div>
</div>
</div>
- <div class="wear-section">
+ <div class="landing-section">
<div class="wrap">
<div class="cols">
- <div class="wear-body">
+ <div class="landing-body">
<div class="col-3-wide">
<a target="_blank" href="https://www.youtube.com/playlist?list=PLWz5rJ2EKKc-kIrPiq098QH9dOle-fLef">
- <img class="wear-social-image" src="//www.google.com/images/icons/product/youtube-128.png" alt="">
+ <img class="landing-social-image" src="//www.google.com/images/icons/product/youtube-128.png" alt="">
</a>
- <div class="wear-social-copy">
+ <div class="landing-social-copy">
<p>DevBytes</p>
- <p class="wear-small">
- Learn how to optimize your app notifications for wearable devices in this <a target="_blank" href="https://www.youtube.com/playlist?list=PLWz5rJ2EKKc-kIrPiq098QH9dOle-fLef">DevBytes video</a> using the Android Wear Developer Preview.
- </p>
+ <p class="landing-small">
+ Learn the basic concepts of Android Wear
+ development with videos from the product team.
+ </p>
+ <br>
+ <p class="landing-small">
+ <a target="_blank" href="https://www.youtube.com/playlist?list=PLWz5rJ2EKKc-kIrPiq098QH9dOle-fLef">DevBytes videos</a>
+ </p>
</div>
</div>
<div class="col-3-wide">
- <a target="_blank" href="http://android-developers.blogspot.com/2014/03/android-wear-developer-preview.html">
- <img class="wear-social-image" src="/wear/images/blogger.png" alt="">
+ <a target="_blank" href="http://android-developers.blogspot.com/2014/03/android-landing-developer-preview.html">
+ <img class="landing-social-image" src="{@docRoot}wear/images/blogger.png" alt="">
</a>
- <div class="wear-social-copy">
+ <div class="landing-social-copy">
<p>Blog Post</p>
- <p class="wear-small">
- Read more about the Android Wear Developer Preview announcement
- at the <a target="_blank" href="http://android-developers.blogspot.com/2014/03/android-wear-developer-preview.html">Android Developers Blog</a>.
+ <p class="landing-small">
+ Read more about Android Wear development
+ on our blog. Just search for "Android Wear".
+
</p>
+ <br>
+ <p class="landing-small">
+ <a target="_blank" href="http://android-developers.blogspot.com/2014/03/android-wear-developer-preview.html">Android Developers Blog</a>
+ </p>
+ <p></p>
</div>
</div>
<div class="col-3-wide">
<a target="_blank" href="http://g.co/androidweardev">
- <img class="wear-social-image" src="//www.google.com/images/icons/product/gplus-128.png" alt="+Android Wear Developers">
+ <img class="landing-social-image" src="//www.google.com/images/icons/product/gplus-128.png" alt="+Android Wear Developers">
</a>
- <div class="wear-social-copy">
+ <div class="landing-social-copy">
<p>G+ Community</p>
- <p class="wear-small">
- Follow us on Google+ to stay up-to-date on Android Wear development and join the discussion!
+ <p class="landing-small">
+ Follow us on Google+ to stay up-to-date with Android Wear development and to join the discussion!
+
</p>
- <p class="wear-small">
+ <p class="landing-small">
<a target="_blank" href="http://g.co/androidweardev">+Android Wear Developers</a>
</p>
</div>
@@ -371,14 +259,12 @@
</div>
</div>
</div> <!-- end .wrap -->
- </div> <!-- end .wear-section -->
- </div> <!-- end .wear-rest-of-page -->
-
-
+ </div> <!-- end .landing-section -->
+ </div> <!-- end .landing-rest-of-page -->
<div class="content-footer wrap" itemscope="" itemtype="http://schema.org/SiteNavigationElement">
<div class="layout-content-col col-16" style="padding-top:4px">
<style>#___plusone_0 {float:right !important;}</style>
- <div class="g-plusone" data-size="medium"></div>
+ <div id="___plusone_0" style="text-indent: 0px; margin: 0px; padding: 0px; border-style: none; float: none; line-height: normal; font-size: 1px; vertical-align: baseline; display: inline-block; width: 90px; height: 20px; background: transparent;"><iframe frameborder="0" hspace="0" marginheight="0" marginwidth="0" scrolling="no" style="position: static; top: 0px; width: 90px; margin: 0px; border-style: none; left: 0px; visibility: visible; height: 20px;" tabindex="0" vspace="0" width="100%" id="I0_1402525433965" name="I0_1402525433965" src="https://apis.google.com/u/0/_/+1/fastbutton?usegapi=1&size=medium&origin=http%3A%2F%2Frobertly.mtv%3A8080&url=http%3A%2F%2Frobertly.mtv%3A8080%2Fwear%2Findex.html&gsrc=3p&jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.en.QxHQHBkhz7M.O%2Fm%3D__features__%2Fam%3DUQ%2Frt%3Dj%2Fd%3D1%2Fz%3Dzcms%2Frs%3DAItRSTMLrMyRVKsu2FQoRingre3w1MT49A#_methods=onPlusOne%2C_ready%2C_close%2C_open%2C_resizeMe%2C_renderstart%2Concircled%2Cdrefresh%2Cerefresh%2Conload&id=I0_1402525433965&parent=http%3A%2F%2Frobertly.mtv%3A8080&pfname=&rpctoken=32453860" data-gapiattached="true" title="+1"></iframe></div>
</div>
</div>
<div id="footer" class="wrap" style="width:940px;position:relative;top:-35px;z-index:-1">
@@ -386,20 +272,9 @@
Except as noted, this content is
licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
Creative Commons Attribution 2.5</a>. For details and
- restrictions, see the <a href="/license.html">Content
+ restrictions, see the <a href="{@docRoot}license.html">Content
License</a>.
</div>
</div>
-
-
- </div> <!-- end wear-body-content -->
-
- <script>
- $("a.wear-down-arrow").on("click", function(e) {
- $("body").animate({
- scrollTop: $(".wear-hero").height() + 76
- }, 1000, "easeOutQuint");
- e.preventDefault();
- });
- </script>
+ </div> <!-- end landing-body-content -->
diff --git a/docs/html/wear/license.jd b/docs/html/wear/license.jd
deleted file mode 100644
index b07dacf..0000000
--- a/docs/html/wear/license.jd
+++ /dev/null
@@ -1,142 +0,0 @@
-page.title=Developer Preview License Agreement
-
-@jd:body
-
-
-<div class="sdk-terms" style="height:auto;border:0;padding:0;width:700px">
-This is the Android Wear Developer Preview License Agreement.
-
-1. Introduction
-
-1.1 The Android Wear Developer Preview Kit (referred to in this License Agreement as the “Developer Preview” and specifically including the Android system files, packaged APIs, Developer Preview library files, and the Developer Preview companion app, if and when they are made available) is licensed to you subject to the terms of this License Agreement. This License Agreement forms a legally binding contract between you and Google in relation to your use of the Developer Preview.
-
-1.2 "Android Wear" means the Android Wear devices and the Android Wear software stack for use on Android Wear devices.
-
-1.3 "Android" means the Android software stack for devices, as made available under the Android Open Source Project, which is located at the following URL: http://source.android.com/, as updated from time to time.
-
-1.4 "Google" means Google Inc., a Delaware corporation with principal place of business at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States.
-
-2. Accepting this License Agreement
-
-2.1 In order to use the Developer Preview, you must first agree to this License Agreement. You may not use the Developer Preview if you do not accept this License Agreement.
-
-2.2 By clicking to accept, you hereby agree to the terms of this License Agreement.
-
-2.3 You may not use the Developer Preview and may not accept the License Agreement if you are a person barred from receiving the Developer Preview under the laws of the United States or other countries including the country in which you are resident or from which you use the Developer Preview.
-
-2.4 If you are agreeing to be bound by this License Agreement on behalf of your employer or other entity, you represent and warrant that you have full legal authority to bind your employer or such entity to this License Agreement. If you do not have the requisite authority, you may not accept the License Agreement or use the Developer Preview on behalf of your employer or other entity.
-
-3. Developer Preview License from Google
-
-3.1 Subject to the terms of this License Agreement, Google grants you a limited, worldwide, royalty-free, internal-use, non-assignable and non-exclusive license to use the Developer Preview solely to develop applications to run on the Android Wear platform for Android Wear devices.
-
-3.2 You agree that Google or third parties own all legal right, title and interest in and to the Developer Preview, including any Intellectual Property Rights that subsist in the Developer Preview. "Intellectual Property Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law, and any and all other proprietary rights. Google reserves all rights not expressly granted to you.
-
-3.3 You may not use the Developer Preview for any purpose not expressly permitted by this License Agreement. Except to the extent required by applicable third party licenses, you may not: (a) copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the Developer Preview or any part of the Developer Preview; or (b) load any part of the Developer Preview onto a mobile handset or wearable computing device or any other hardware device except an Android Wear device, combine any part of the Developer Preview with other software, or distribute any software or device incorporating a part of the Developer Preview.
-
-3.4 You agree that you will not take any actions that may cause or result in the fragmentation of Android Wear, including but not limited to distributing, participating in the creation of, or promoting in any way a software development kit derived from the Developer Preview.
-
-3.5 Use, reproduction and distribution of components of the Developer Preview licensed under an open source software license are governed solely by the terms of that open source software license and not this License Agreement.
-
-3.6 You agree that the form and nature of the Developer Preview that Google provides may change without prior notice to you and that future versions of the Developer Preview may be incompatible with applications developed on previous versions of the Developer Preview. You agree that Google may stop (permanently or temporarily) providing the Developer Preview (or any features within the Developer Preview) to you or to users generally at Google's sole discretion, without prior notice to you.
-
-3.7 Nothing in this License Agreement gives you a right to use any of Google's trade names, trademarks, service marks, logos, domain names, or other distinctive brand features.
-
-3.8 You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that may be affixed to or contained within the Developer Preview.
-
-3.9 Your use of any Android system files, packaged APIs, or other components of the Developer Preview which are part of the Android Software Development Kit is subject to the terms of the Android Software Development Kit License Agreement located at http://developer.android.com/sdk/terms.html. These terms are hereby incorporated by reference into this License Agreement.
-
-4. Use of the Developer Preview by You
-
-4.1 Google agrees that it obtains no right, title or interest from you (or your licensors) under this License Agreement in or to any software applications that you develop using the Developer Preview, including any intellectual property rights that subsist in those applications.
-
-4.2 You agree to use the Developer Preview and write applications only for purposes that are permitted by (a) this License Agreement, (b) the Google Play Developer Program Policies located at https://play.google.com/about/developer-content-policy.html, and hereby incorporated into this License Agreement by reference), and (c) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United States or other relevant countries). You agree to use reasonable efforts to comply with the Android Wear Platform Design Guide available on the Android Wear developer website
-
-4.3 You agree that if you use the Developer Preview to develop applications for general public users, you will protect the privacy and legal rights of those users. If the users provide you with user names, passwords, or other login information or personal information, you must make the users aware that the information will be available to your application, and you must provide legally adequate privacy notice and protection for those users. If your application stores personal or sensitive information provided by users, it must do so securely. If the user provides your application with Google Account information, your application may only use that information to access the user's Google Account when, and for the limited purposes for which, the user has given you permission to do so.
-
-4.4 You agree that you will not engage in any activity with the Developer Preview, including the development or distribution of an application, that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of any third party including, but not limited to, Google.
-
-4.5 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any data, content, or resources that you create, transmit or display through Android Wear and/or applications for Android Wear, and for the consequences of your actions (including any loss or damage which Google may suffer) by doing so.
-
-4.6 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any breach of your obligations under this License Agreement, any applicable third party contract or Terms of Service, or any applicable law or regulation, and for the consequences (including any loss or damage which Google or any third party may suffer) of any such breach.
-
-4.7 Unless otherwise specified in writing by Google, Google does not intend use of Android Wear to create obligations under the Health Insurance Portability and Accountability Act, as amended, (“HIPAA”), and makes no representations that Android Wear satisfies HIPAA requirements. If you are (or become) a Covered Entity or Business Associate under HIPAA, you agree not to use Android Wear for any purpose or in any manner involving Protected Health Information unless you have received prior written consent to such use from Google.
-
-4.8 The Developer Preview is in development, and your testing and feedback are an important part of the development process. By using the Developer Preview, you acknowledge that implementation of some features are still under development and that you should not rely on the Developer Preview, Android Wear devices, Android Wear system software, or Android Wear services having the full functionality of a stable release. You agree not to publicly distribute or ship any application using this Developer Preview as this Developer Preview will no longer be supported after the official SDK is released.
-
-5. Your Developer Credentials
-
-5.1 You agree that you are responsible for maintaining the confidentiality of any developer credentials that may be issued to you by Google or which you may choose yourself and that you will be solely responsible for all applications that are developed under your developer credentials.
-
-6. Privacy and Information
-
-6.1 In order to continually innovate and improve the Developer Preview, Google may collect certain usage statistics from the software including but not limited to a unique identifier, associated IP address, version number of the software, and information on which tools and/or services in the Developer Preview are being used and how they are being used. Before any of this information is collected, the Developer Preview will notify you and seek your consent. If you withhold consent, the information will not be collected.
-
-6.2 The data collected is examined in the aggregate to improve the Developer Preview and is maintained in accordance with Google's Privacy Policy lcoated at http://www.google.com/policies/privacy/.
-
-7. Third Party Applications
-
-7.1 If you use the Developer Preview to run applications developed by a third party or that access data, content or resources provided by a third party, you agree that Google is not responsible for those applications, data, content, or resources. You understand that all data, content or resources which you may access through such third party applications are the sole responsibility of the person from which they originated and that Google is not liable for any loss or damage that you may experience as a result of the use or access of any of those third party applications, data, content, or resources.
-
-7.2 You should be aware the data, content, and resources presented to you through such a third party application may be protected by intellectual property rights which are owned by the providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on these data, content, or resources (either in whole or in part) unless you have been specifically given permission to do so by the relevant owners.
-
-7.3 You acknowledge that your use of such third party applications, data, content, or resources may be subject to separate terms between you and the relevant third party. In that case, this License Agreement does not affect your legal relationship with these third parties.
-
-8. Using Google APIs
-
-8.1 Google APIs
-
-8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be protected by intellectual property rights which are owned by Google or those parties that provide the data (or by other persons or companies on their behalf). Your use of any such API may be subject to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this data (either in whole or in part) unless allowed by the relevant Terms of Service.
-
-8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree that you shall retrieve data only with the user's explicit consent and only when, and for the limited purposes for which, the user has given you permission to do so.
-
-9. Terminating this License Agreement
-
-9.1 This License Agreement will continue to apply until terminated by either you or Google as set out below.
-
-9.2 If you want to terminate this License Agreement, you may do so by ceasing your use of the Developer Preview and any relevant developer credentials.
-
-9.3 Google may at any time, terminate this License Agreement with you if:
-(A) you have breached any provision of this License Agreement; or
-(B) Google is required to do so by law; or
-(C) the partner with whom Google offered certain parts of Developer Preview (such as APIs) to you has terminated its relationship with Google or ceased to offer certain parts of the Developer Preview to you; or
-(D) Google decides to no longer provide the Developer Preview or certain parts of the Developer Preview to users in the country in which you are resident or from which you use the service, or the provision of the Developer Preview or certain Developer Preview services to you by Google is, in Google's sole discretion, no longer commercially viable.
-
-9.4 When this License Agreement comes to an end, all of the legal rights, obligations and liabilities that you and Google have benefited from, been subject to (or which have accrued over time whilst this License Agreement has been in force) or which are expressed to continue indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 14.7 shall continue to apply to such rights, obligations and liabilities indefinitely.
-
-10. DISCLAIMER OF WARRANTIES
-
-10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE DEVELOPER PREVIEW IS AT YOUR SOLE RISK AND THAT THE DEVELOPER PREVIEW IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE.
-
-10.2 YOUR USE OF THE DEVELOPER PREVIEW AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE DEVELOPER PREVIEW IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE.
-
-10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
-
-11. LIMITATION OF LIABILITY
-
-11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING.
-
-12. Indemnification
-
-12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold harmless Google, its affiliates and their respective directors, officers, employees and agents from and against any and all claims, actions, suits or proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys’ fees) arising out of or accruing from (a) your use of the Developer Preview, (b) any application you develop on the Developer Preview that infringes any copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any person or defames any person or violates their rights of publicity or privacy, and (c) any non-compliance by you with this License Agreement.
-
-13. Changes to the License Agreement
-
-13.1 Google may make changes to the License Agreement as it distributes new versions of the Developer Preview. When these changes are made, Google will make a new version of the License Agreement available on the website where the Developer Preview is made available.
-
-14. General Legal Terms
-
-14.1 This License Agreement constitutes the whole legal agreement between you and Google and governs your use of the Developer Preview (excluding any services which Google may provide to you under a separate written agreement), and completely replaces any prior agreements between you and Google in relation to the Developer Preview.
-
-14.2 You agree that if Google does not exercise or enforce any legal right or remedy which is contained in this License Agreement (or which Google has the benefit of under any applicable law), this will not be taken to be a formal waiver of Google's rights and that those rights or remedies will still be available to Google.
-
-14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any provision of this License Agreement is invalid, then that provision will be removed from this License Agreement without affecting the rest of this License Agreement. The remaining provisions of this License Agreement will continue to be valid and enforceable.
-
-14.4 You acknowledge and agree that each member of the group of companies of which Google is the parent shall be third party beneficiaries to this License Agreement and that such other companies shall be entitled to directly enforce, and rely upon, any provision of this License Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to this License Agreement.
-
-14.5 EXPORT RESTRICTIONS. THE DEVELOPER PREVIEW IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE DEVELOPER PREVIEW. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE.
-
-14.6 The rights granted in this License Agreement may not be assigned or transferred by either you or Google without the prior written approval of the other party. Neither you nor Google shall be permitted to delegate their responsibilities or obligations under this License Agreement without the prior written approval of the other party.
-
-14.7 This License Agreement, and your relationship with Google under this License Agreement, shall be governed by the laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter arising from this License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.
-</div>
diff --git a/docs/html/wear/preview/signup.jd b/docs/html/wear/preview/signup.jd
deleted file mode 100644
index 8e8ec9a..0000000
--- a/docs/html/wear/preview/signup.jd
+++ /dev/null
@@ -1,169 +0,0 @@
-page.title=Sign Up for the Developer Preview
-
-@jd:body
-
-<p>To get started with the Android Wear Developer Preview, you must agree to the
- following terms and conditions and provide the email address for your Google account.
-After signing up, you’ll have access to:</p>
-<ul>
- <li>New APIs that allow you to build enhanced notifications for wearables.</li>
- <li>Sample code using the new APIs.</li>
- <li>The Android Wear Preview app that delivers your notifications to the Android Wear emulator.</li>
-</ul>
-
-<div class="sdk-terms" style="width:678px" onfocus="this.blur()"><div class="sdk-terms-padding">
-This is the Android Wear Developer Preview License Agreement.
-
-1. Introduction
-
-1.1 The Android Wear Developer Preview Kit (referred to in this License Agreement as the “Developer Preview” and specifically including the Android system files, packaged APIs, Developer Preview library files, and the Developer Preview companion app, if and when they are made available) is licensed to you subject to the terms of this License Agreement. This License Agreement forms a legally binding contract between you and Google in relation to your use of the Developer Preview.
-
-1.2 "Android Wear" means the Android Wear devices and the Android Wear software stack for use on Android Wear devices.
-
-1.3 "Android" means the Android software stack for devices, as made available under the Android Open Source Project, which is located at the following URL: http://source.android.com/, as updated from time to time.
-
-1.4 "Google" means Google Inc., a Delaware corporation with principal place of business at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States.
-
-2. Accepting this License Agreement
-
-2.1 In order to use the Developer Preview, you must first agree to this License Agreement. You may not use the Developer Preview if you do not accept this License Agreement.
-
-2.2 By clicking to accept, you hereby agree to the terms of this License Agreement.
-
-2.3 You may not use the Developer Preview and may not accept the License Agreement if you are a person barred from receiving the Developer Preview under the laws of the United States or other countries including the country in which you are resident or from which you use the Developer Preview.
-
-2.4 If you are agreeing to be bound by this License Agreement on behalf of your employer or other entity, you represent and warrant that you have full legal authority to bind your employer or such entity to this License Agreement. If you do not have the requisite authority, you may not accept the License Agreement or use the Developer Preview on behalf of your employer or other entity.
-
-3. Developer Preview License from Google
-
-3.1 Subject to the terms of this License Agreement, Google grants you a limited, worldwide, royalty-free, internal-use, non-assignable and non-exclusive license to use the Developer Preview solely to develop applications to run on the Android Wear platform for Android Wear devices.
-
-3.2 You agree that Google or third parties own all legal right, title and interest in and to the Developer Preview, including any Intellectual Property Rights that subsist in the Developer Preview. "Intellectual Property Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law, and any and all other proprietary rights. Google reserves all rights not expressly granted to you.
-
-3.3 You may not use the Developer Preview for any purpose not expressly permitted by this License Agreement. Except to the extent required by applicable third party licenses, you may not: (a) copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the Developer Preview or any part of the Developer Preview; or (b) load any part of the Developer Preview onto a mobile handset or wearable computing device or any other hardware device except an Android Wear device, combine any part of the Developer Preview with other software, or distribute any software or device incorporating a part of the Developer Preview.
-
-3.4 You agree that you will not take any actions that may cause or result in the fragmentation of Android Wear, including but not limited to distributing, participating in the creation of, or promoting in any way a software development kit derived from the Developer Preview.
-
-3.5 Use, reproduction and distribution of components of the Developer Preview licensed under an open source software license are governed solely by the terms of that open source software license and not this License Agreement.
-
-3.6 You agree that the form and nature of the Developer Preview that Google provides may change without prior notice to you and that future versions of the Developer Preview may be incompatible with applications developed on previous versions of the Developer Preview. You agree that Google may stop (permanently or temporarily) providing the Developer Preview (or any features within the Developer Preview) to you or to users generally at Google's sole discretion, without prior notice to you.
-
-3.7 Nothing in this License Agreement gives you a right to use any of Google's trade names, trademarks, service marks, logos, domain names, or other distinctive brand features.
-
-3.8 You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that may be affixed to or contained within the Developer Preview.
-
-3.9 Your use of any Android system files, packaged APIs, or other components of the Developer Preview which are part of the Android Software Development Kit is subject to the terms of the Android Software Development Kit License Agreement located at http://developer.android.com/sdk/terms.html. These terms are hereby incorporated by reference into this License Agreement.
-
-4. Use of the Developer Preview by You
-
-4.1 Google agrees that it obtains no right, title or interest from you (or your licensors) under this License Agreement in or to any software applications that you develop using the Developer Preview, including any intellectual property rights that subsist in those applications.
-
-4.2 You agree to use the Developer Preview and write applications only for purposes that are permitted by (a) this License Agreement, (b) the Google Play Developer Program Policies located at https://play.google.com/about/developer-content-policy.html, and hereby incorporated into this License Agreement by reference), and (c) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United States or other relevant countries). You agree to use reasonable efforts to comply with the Android Wear Platform Design Guide available on the Android Wear developer website
-
-4.3 You agree that if you use the Developer Preview to develop applications for general public users, you will protect the privacy and legal rights of those users. If the users provide you with user names, passwords, or other login information or personal information, you must make the users aware that the information will be available to your application, and you must provide legally adequate privacy notice and protection for those users. If your application stores personal or sensitive information provided by users, it must do so securely. If the user provides your application with Google Account information, your application may only use that information to access the user's Google Account when, and for the limited purposes for which, the user has given you permission to do so.
-
-4.4 You agree that you will not engage in any activity with the Developer Preview, including the development or distribution of an application, that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of any third party including, but not limited to, Google.
-
-4.5 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any data, content, or resources that you create, transmit or display through Android Wear and/or applications for Android Wear, and for the consequences of your actions (including any loss or damage which Google may suffer) by doing so.
-
-4.6 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any breach of your obligations under this License Agreement, any applicable third party contract or Terms of Service, or any applicable law or regulation, and for the consequences (including any loss or damage which Google or any third party may suffer) of any such breach.
-
-4.7 Unless otherwise specified in writing by Google, Google does not intend use of Android Wear to create obligations under the Health Insurance Portability and Accountability Act, as amended, (“HIPAA”), and makes no representations that Android Wear satisfies HIPAA requirements. If you are (or become) a Covered Entity or Business Associate under HIPAA, you agree not to use Android Wear for any purpose or in any manner involving Protected Health Information unless you have received prior written consent to such use from Google.
-
-4.8 The Developer Preview is in development, and your testing and feedback are an important part of the development process. By using the Developer Preview, you acknowledge that implementation of some features are still under development and that you should not rely on the Developer Preview, Android Wear devices, Android Wear system software, or Android Wear services having the full functionality of a stable release. You agree not to publicly distribute or ship any application using this Developer Preview as this Developer Preview will no longer be supported after the official SDK is released.
-
-5. Your Developer Credentials
-
-5.1 You agree that you are responsible for maintaining the confidentiality of any developer credentials that may be issued to you by Google or which you may choose yourself and that you will be solely responsible for all applications that are developed under your developer credentials.
-
-6. Privacy and Information
-
-6.1 In order to continually innovate and improve the Developer Preview, Google may collect certain usage statistics from the software including but not limited to a unique identifier, associated IP address, version number of the software, and information on which tools and/or services in the Developer Preview are being used and how they are being used. Before any of this information is collected, the Developer Preview will notify you and seek your consent. If you withhold consent, the information will not be collected.
-
-6.2 The data collected is examined in the aggregate to improve the Developer Preview and is maintained in accordance with Google's Privacy Policy lcoated at http://www.google.com/policies/privacy/.
-
-7. Third Party Applications
-
-7.1 If you use the Developer Preview to run applications developed by a third party or that access data, content or resources provided by a third party, you agree that Google is not responsible for those applications, data, content, or resources. You understand that all data, content or resources which you may access through such third party applications are the sole responsibility of the person from which they originated and that Google is not liable for any loss or damage that you may experience as a result of the use or access of any of those third party applications, data, content, or resources.
-
-7.2 You should be aware the data, content, and resources presented to you through such a third party application may be protected by intellectual property rights which are owned by the providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on these data, content, or resources (either in whole or in part) unless you have been specifically given permission to do so by the relevant owners.
-
-7.3 You acknowledge that your use of such third party applications, data, content, or resources may be subject to separate terms between you and the relevant third party. In that case, this License Agreement does not affect your legal relationship with these third parties.
-
-8. Using Google APIs
-
-8.1 Google APIs
-
-8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be protected by intellectual property rights which are owned by Google or those parties that provide the data (or by other persons or companies on their behalf). Your use of any such API may be subject to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this data (either in whole or in part) unless allowed by the relevant Terms of Service.
-
-8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree that you shall retrieve data only with the user's explicit consent and only when, and for the limited purposes for which, the user has given you permission to do so.
-
-9. Terminating this License Agreement
-
-9.1 This License Agreement will continue to apply until terminated by either you or Google as set out below.
-
-9.2 If you want to terminate this License Agreement, you may do so by ceasing your use of the Developer Preview and any relevant developer credentials.
-
-9.3 Google may at any time, terminate this License Agreement with you if:
-(A) you have breached any provision of this License Agreement; or
-(B) Google is required to do so by law; or
-(C) the partner with whom Google offered certain parts of Developer Preview (such as APIs) to you has terminated its relationship with Google or ceased to offer certain parts of the Developer Preview to you; or
-(D) Google decides to no longer provide the Developer Preview or certain parts of the Developer Preview to users in the country in which you are resident or from which you use the service, or the provision of the Developer Preview or certain Developer Preview services to you by Google is, in Google's sole discretion, no longer commercially viable.
-
-9.4 When this License Agreement comes to an end, all of the legal rights, obligations and liabilities that you and Google have benefited from, been subject to (or which have accrued over time whilst this License Agreement has been in force) or which are expressed to continue indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 14.7 shall continue to apply to such rights, obligations and liabilities indefinitely.
-
-10. DISCLAIMER OF WARRANTIES
-
-10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE DEVELOPER PREVIEW IS AT YOUR SOLE RISK AND THAT THE DEVELOPER PREVIEW IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE.
-
-10.2 YOUR USE OF THE DEVELOPER PREVIEW AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE DEVELOPER PREVIEW IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE.
-
-10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
-
-11. LIMITATION OF LIABILITY
-
-11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING.
-
-12. Indemnification
-
-12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold harmless Google, its affiliates and their respective directors, officers, employees and agents from and against any and all claims, actions, suits or proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys’ fees) arising out of or accruing from (a) your use of the Developer Preview, (b) any application you develop on the Developer Preview that infringes any copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any person or defames any person or violates their rights of publicity or privacy, and (c) any non-compliance by you with this License Agreement.
-
-13. Changes to the License Agreement
-
-13.1 Google may make changes to the License Agreement as it distributes new versions of the Developer Preview. When these changes are made, Google will make a new version of the License Agreement available on the website where the Developer Preview is made available.
-
-14. General Legal Terms
-
-14.1 This License Agreement constitutes the whole legal agreement between you and Google and governs your use of the Developer Preview (excluding any services which Google may provide to you under a separate written agreement), and completely replaces any prior agreements between you and Google in relation to the Developer Preview.
-
-14.2 You agree that if Google does not exercise or enforce any legal right or remedy which is contained in this License Agreement (or which Google has the benefit of under any applicable law), this will not be taken to be a formal waiver of Google's rights and that those rights or remedies will still be available to Google.
-
-14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any provision of this License Agreement is invalid, then that provision will be removed from this License Agreement without affecting the rest of this License Agreement. The remaining provisions of this License Agreement will continue to be valid and enforceable.
-
-14.4 You acknowledge and agree that each member of the group of companies of which Google is the parent shall be third party beneficiaries to this License Agreement and that such other companies shall be entitled to directly enforce, and rely upon, any provision of this License Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to this License Agreement.
-
-14.5 EXPORT RESTRICTIONS. THE DEVELOPER PREVIEW IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE DEVELOPER PREVIEW. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE.
-
-14.6 The rights granted in this License Agreement may not be assigned or transferred by either you or Google without the prior written approval of the other party. Neither you nor Google shall be permitted to delegate their responsibilities or obligations under this License Agreement without the prior written approval of the other party.
-
-14.7 This License Agreement, and your relationship with Google under this License Agreement, shall be governed by the laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter arising from this License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.
-
-
-</div></div>
-
-
-<p class="caution">
- <strong>Important:</strong> Your email address is used to provide your Google account
- access to the Android Wear Preview app Beta Preview on Google Play Store. As such, the
- email address you provide below must be for the account you use to download apps on Google Play Store.
- We may also use your email address to provide you with updates about the Android Wear
- platform release.
-</p>
-
-<iframe src="https://docs.google.com/forms/d/1iSJ084kEkV242cZisNMnj6G8qpi9r_zdEyfXA-hB1ao/viewform?embedded=true" width="100%" height="540" frameborder="0" marginheight="0" marginwidth="0" id="signupform">Loading...</iframe>
-
-
-
-
-</body>
-</html>
diff --git a/docs/html/wear/preview/start.jd b/docs/html/wear/preview/start.jd
deleted file mode 100644
index f8f0129..0000000
--- a/docs/html/wear/preview/start.jd
+++ /dev/null
@@ -1,254 +0,0 @@
-page.title=Get Started with the Developer Preview
-
-@jd:body
-
-
-<div class="cols">
-
- <div class="col-5">
-<p>The Android Wear Developer Preview includes tools and APIs that allow you to
-enhance your app notifications
-to provide an optimized user experience on Android wearables.</p>
-
-<p>With the Android Wear Developer Preview, you can:</p>
-
-<ul>
- <li>Run the Android Wear platform in the Android emulator.</li>
- <li>Connect your Android device to the emulator and view notifications from the
-device as cards on Android Wear.</li>
- <li>Try new APIs in the preview support library that enhance your app's notifications
-with features such as voice replies and notification pages.</li>
-</ul>
-
-<p>To get access to the Developer Preview tools,
-click the sign up button on the right, then follow the setup instructions below.</p>
- </div>
-
- <div class="col-7">
-<img src="/wear/images/laptop-bridge.png" width="400" height="222" alt="" />
-
-<a href="/wear/preview/signup.html" class="button" style="
- width: 370px;
- margin: 10px 0 20px;
- font-weight: bold;
- font-size: 16px;
-">Sign Up for the Developer Preview</a>
-
-<p>Signing up provides you access to:</p>
-<ul>
-<li>New notification APIs in the preview support library.</li>
-<li>Sample apps using the new notification APIs.</li>
-<li>The <em>Android Wear Preview</em> app for your mobile device, which connects
-your device to the Android Wear emulator.</li>
-</ul>
-
- </div>
-</div>
-
-
-<p class="caution"><strong>Caution:</strong>
-The current Android Wear Developer Preview is intended for <b>development and testing purposes only</b>, not for production apps. Google may change this Developer Preview significantly prior to the official release of the Android Wear SDK. You may not publicly distribute or ship any application using this Developer Preview, as this Developer Preview will no longer be supported after the official SDK is released (which will cause applications based only on the Developer Preview to break).</p>
-
-
-
-
-<h2 id="Prereq">Prerequisites</h2>
-
-<p>Before you begin the setup, you must:</p>
-
-<ol>
- <li><a href="{@docRoot}sdk/index.html"><b>Install the Android SDK</b></a>.
- <p>The Android SDK includes all the developer tools required to build
-apps for Android (optional IDEs are also available for download).</p></li>
- <li><a href="{@docRoot}wear/preview/signup.html"><b>Sign up for the Android Wear Developer Preview</b></a>.
- <p>You must sign up with a Gmail or other Google account in order to download the
-preview support library and receive access to the
-<em>Android Wear Preview</em> beta app on Google Play Store.</p></li>
-</ol>
-
-<p class="note"><strong>Note:</strong>
-If you're using the ADT plugin for Eclipse, you must update to version 22.6.1 or higher.
-If you're using Android Studio, you must update to version 0.5.1 or higher</p>
-
-
-
-<h2 id="Install">1. Install the Android Wear System Image</h2>
-
-
-<ol>
- <li>Launch <a href="{@docRoot}tools/help/sdk-manager.html"
- >Android SDK Manager</a>.
- <ul>
- <li>From Eclipse, select <b>Window > Android SDK Manager</b>.</li>
- <li>From Android Studio, select <b>Tools > Android > SDK Manager</b>.</li>
- </ul>
- </li>
- <li>Below Tools, verify that you have Android SDK Tools revision 22.6 or higher.
- <p>If your version of Android SDK Tools is lower than 22.6, you must update:</p>
- <ol>
- <li>Select <strong>Android SDK Tools</strong>.</li>
- <li>Click <strong>Install package</strong>.</li>
- <li>Accept the license and click <strong>Install</strong>.</li>
- <li>When the installation completes, restart Android SDK Manager.</li>
- </ol>
- </li>
-
- <li>Below Android 4.4.2, select <strong>Android Wear ARM EABI v7a System Image</strong>.
-<p class="note"><strong>Note:</strong> Android Wear is designed to support multiple processor architectures.
-</p></li>
- <li>Below Extras, ensure that you have the latest version of the
-<a href="{@docRoot}tools/support-library/index.html">Android Support Library</a>.
- If an update is available, select <strong>Android Support Library</strong>. If you're using Android Studio, also select <strong>Android Support Repository</strong>.</li>
- <li>Click <strong>Install packages</strong>.</li>
- <li>Accept the license and click <strong>Install</strong>.</li>
-</ol>
-
-
-
-<h2 id="SetupEmulator">2. Set Up the Android Wear Emulator</h2>
-
-<ol>
-<li>Launch the <a href="{@docRoot}tools/help/avd-manager.html"
- >Android Virtual Device Manager</a>.
-<ul>
-<li>From Eclipse, select <b>Window > Android Virtual Device Manager</b>.</li>
-<li>From Android Studio, select <b>Tools > Android > AVD Manager</b>.</li>
-</ul>
-</li>
-<li>Click <strong>New</strong>.</li>
-<li>For the AVD Name, enter "AndroidWearSquare" or "AndroidWearRound", depending on whether
-you want to create an emulator with a square or round display.</li>
-<li>For the Device, select <strong>Android Wear Square</strong> or
- <strong>Android Wear Round</strong>.</li>
-<li>For the Target, select <strong>Android 4.4.2 - API Level 19</strong> (or higher).</li>
-<li>For the CPU/ABI, select <strong>Android Wear ARM (armeabi-v7a)</strong>.
-<p class="note"><strong>Note:</strong> Android Wear is designed to support multiple processor architectures.
-</p></li>
-<li>For the Skin, select <strong>AndroidWearSquare</strong> or
-<strong>AndroidWearRound</strong>.</li>
-<li>Leave all other options set to their defaults and click <strong>OK</strong>.
- <p>Although real Android wearables do not provide a keyboard as an input method,
- you should keep <strong>Hardware keyboard present</strong> selected so you can
- provide text input on screens where users will instead provide voice input.</p>
-</li>
-<!--
-<li>Click <strong>Device Definitions</strong>.</li>
-<li>Select <strong>Android WearSquare</strong> then click <strong>Create AVD</strong>.</li>
-<li>Click <strong>OK</strong>.</li>
--->
-<li>In the list of AVDs, select the one you just created and click
- <strong>Start</strong>. In the following window, click <strong>Launch</strong>.</li>
-</ol>
-
-<p>The Android Wear emulator now starts. To begin testing your app's notifications,
-you must now pair the emulator to your development device
-that has the <em>Android Wear Preview</em> app installed.</p>
-
-<p class="note"><strong>Tip:</strong> To improve the emulator startup time, edit your AVD
-and enable <strong>Snapshot</strong> under Emulator Options. When you start the emulator,
-select <strong>Save to snapshot</strong> then click <strong>Launch</strong>. Once the emulator
-is running, close it to save a snapshot of the system.
-Start the AVD again, but select <strong>Launch from snapshot</strong> and
-deselect <strong>Save to snapshot</strong>.</p>
-
-<p class="caution"><strong>Caution:</strong> Do not install apps on the Android Wear emulator.
-The system does not support traditional Android apps and the result of running such apps is
-unpredictable.</p>
-
-
-
-<h2 id="SetupApp">3. Set Up the Android Wear Preview App</h2>
-
-<p>To view your app's notifications on the Android Wear emulator, you must have the
-<em>Android Wear Preview</em> app installed on your Android device (a phone or tablet).</p>
-
-<p>To receive the Android Wear Preview app, you must <a
-href="{@docRoot}wear/preview/signup.html">sign up for the Developer Preview</a> using the same
-Gmail or Google account you use with Google Play Store.</p>
-</p>
-
-<p class="note"><strong>Note:</strong> The <em>Android Wear Preview</em> app is compatible with
- Android 4.3 and higher and is not available for the Android emulator.</p>
-
-<p>After you've signed up for the Developer Preview,
- you'll receive a confirmation email that includes a link to opt-in to the
- <em>Android Wear Preview</em> app beta program. Once you opt-in, it may take up to 24 hours for the
- app to become available in Google Play Store.</p>
-
-<p>After you install the <em>Android Wear Preview</em> app, you can set up
- your device to communicate with the Android Wear emulator:</p>
-
-<ol>
-<li>Open the <em>Android Wear Preview</em> app. You should see a notice that the app is currently
- not enabled as a notification listener. Tap the message to open the system settings,
- then select Android Wear Preview to grant it notification access.</li>
-<li>Connect your device to your development machine over USB. Be sure that no other
- Android devices are connected to the machine.</li>
-<li>Ensure that the Android Wear emulator (created in the previous section) is running.
-The emulator should show the time and an icon that indicates no device is connected.</li>
-<li>Open a command line terminal, navigate to your Android SDK's <code>platform-tools/</code>
-directory, then execute:
-<pre style="margin-top:.5em">adb -d forward tcp:5601 tcp:5601</pre>
-<p class="note"><strong>Note:</strong> You must execute this command each time you connect your
-device over USB.</p>
-</li>
-<li>Return to the Android Wear Preview app. It should now indicate that it is connected to
- the emulator. The Android Wear emulator should now show the 'g' orb icon, indicating
- that is is connected to your device.
-</ol>
-
-<p>Now, notifications from your device also appear in the Android Wear emulator.</p>
-
-
-
-
-<h2 id="AddLibrary">4. Add the Support Library to Your Project</h2>
-
-<p>The Android Wear preview support library includes several APIs that allow you to
-optimize your app's notifications for the Android Wear user experience.</p>
-
-<p>To receive the preview support library, you must <a
-href="{@docRoot}wear/preview/signup.html">sign up for the Developer Preview</a>. The
-confirmation email you receive after you sign up includes a link to download a ZIP file,
-which contains the preview support library and some sample apps.</p>
-
-<p>After you download and unzip the package, add the preview support library
-sto your Android project:</p>
-
-<p><b>If you're using Eclipse:</b></p>
- <ol>
- <li>In your Android app project, create a <code>libs/</code> directory in your project root
- (the same location as the <code>AndroidManifest.xml</code> file).</li>
- <li>Copy the v4 support library JAR file from your Android SDK directory (e.g.,
- <code><sdk>/extras/android/support/v4/android-support-v4.jar</code>) into your
- project <code>libs/</code> directory.
- <li>Also save the <code>wearable-preview-support.jar</code> file in the <code>libs/</code> directory.
- <li>Right click each JAR file and select <strong>Build Path > Add to Build Path</strong>.</li>
- </ol>
-
- <p><b>If you're using Android Studio:</b></p>
- <ol>
- <li>In your Android app project, create a <code>libs/</code> directory in your project root
- (the same location as the <code>AndroidManifest.xml</code> file).</li>
- <li>Save the <code>wearable-preview-support.jar</code> file in the <code>libs/</code> directory.
- <li>Open the <code>build.gradle</code> file in your app module.</li>
- <li>Add a dependency rule for both the v4 support library and the Android Wear
- preview support library:
-<pre>
-dependencies {
- compile "com.android.support:support-v4:18.0.+"
- compile files('../libs/wearable-preview-support.jar')
-}
-</pre>
- </li>
- <li>Click <strong>Sync Project with Gradle Files</strong> in the toolbar.</li>
- </ol>
-
-<p>To start optimizing your notifications for Android Wear,
- read <a href="{@docRoot}wear/notifications/creating.html"
- >Creating Notifications for Android Wear</a>.</p>
-
-
-
-</body>
-</html>
diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp
index de8531b..d321baf 100644
--- a/drm/jni/android_drm_DrmManagerClient.cpp
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -233,7 +233,7 @@
static void android_drm_DrmManagerClient_release(
JNIEnv* env, jobject thiz, jint uniqueId) {
ALOGV("release - Enter");
- DrmManagerClientImpl::remove(uniqueId);
+ getDrmManagerClientImpl(env, thiz)->remove(uniqueId);
getDrmManagerClientImpl(env, thiz)->setOnInfoListener(uniqueId, NULL);
sp<DrmManagerClientImpl> oldClient = setDrmManagerClientImpl(env, thiz, NULL);
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 06cf253..ef0a411 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -194,6 +194,11 @@
* while {@link #getAllocationByteCount()} will reflect that of the initial
* configuration.</p>
*
+ * <p>Note: This may change this result of hasAlpha(). When converting to 565,
+ * the new bitmap will always be considered opaque. When converting from 565,
+ * the new bitmap will be considered non-opaque, and will respect the value
+ * set by setPremultiplied().</p>
+ *
* <p>WARNING: This method should NOT be called on a bitmap currently used
* by the view system. It does not make guarantees about how the underlying
* pixel buffer is remapped to the new config, just that the allocation is
@@ -217,7 +222,8 @@
throw new IllegalStateException("native-backed bitmaps may not be reconfigured");
}
- nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length);
+ nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length,
+ mIsPremultiplied);
mWidth = width;
mHeight = height;
}
@@ -1586,7 +1592,8 @@
private static native void nativeDestructor(long nativeBitmap);
private static native boolean nativeRecycle(long nativeBitmap);
private static native void nativeReconfigure(long nativeBitmap, int width, int height,
- int config, int allocSize);
+ int config, int allocSize,
+ boolean isPremultiplied);
private static native boolean nativeCompress(long nativeBitmap, int format,
int quality, OutputStream stream,
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 12877de..158801c 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -16,11 +16,17 @@
package android.graphics;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.text.GraphicsOperations;
import android.text.SpannableString;
import android.text.SpannedString;
import android.text.TextUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
import javax.microedition.khronos.opengles.GL;
/**
@@ -59,11 +65,11 @@
/**
* Used to determine when compatibility scaling is in effect.
- *
+ *
* @hide
*/
protected int mScreenDensity = Bitmap.DENSITY_NONE;
-
+
// Used by native code
@SuppressWarnings("UnusedDeclaration")
private int mSurfaceFormat;
@@ -73,7 +79,7 @@
* @hide
*/
public static final int DIRECTION_LTR = 0;
-
+
/**
* Flag for drawTextRun indicating right-to-left run direction.
* @hide
@@ -130,13 +136,13 @@
/**
* Construct a canvas with the specified bitmap to draw into. The bitmap
* must be mutable.
- *
+ *
* <p>The initial target density of the canvas is the same as the given
* bitmap's density.
*
* @param bitmap Specifies a mutable bitmap for the canvas to draw into.
*/
- public Canvas(Bitmap bitmap) {
+ public Canvas(@NonNull Bitmap bitmap) {
if (!bitmap.isMutable()) {
throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
}
@@ -171,10 +177,10 @@
/**
* Indicates whether this Canvas uses hardware acceleration.
- *
+ *
* Note that this method does not define what type of hardware acceleration
* may or may not be used.
- *
+ *
* @return True if drawing operations are hardware accelerated,
* false otherwise.
*/
@@ -183,7 +189,7 @@
}
/**
- * Specify a bitmap for the canvas to draw into. All canvas state such as
+ * Specify a bitmap for the canvas to draw into. All canvas state such as
* layers, filters, and the save/restore stack are reset with the exception
* of the current matrix and clip stack. Additionally, as a side-effect
* the canvas' target density is updated to match that of the bitmap.
@@ -192,7 +198,7 @@
* @see #setDensity(int)
* @see #getDensity()
*/
- public void setBitmap(Bitmap bitmap) {
+ public void setBitmap(@Nullable Bitmap bitmap) {
if (isHardwareAccelerated()) {
throw new RuntimeException("Can't set a bitmap device on a GL canvas");
}
@@ -273,7 +279,7 @@
* to determine the scaling factor when drawing a bitmap into it.
*
* @see #setDensity(int)
- * @see Bitmap#getDensity()
+ * @see Bitmap#getDensity()
*/
public int getDensity() {
return mDensity;
@@ -289,7 +295,7 @@
* {@link Bitmap#DENSITY_NONE} to disable bitmap scaling.
*
* @see #getDensity()
- * @see Bitmap#setDensity(int)
+ * @see Bitmap#setDensity(int)
*/
public void setDensity(int density) {
if (mBitmap != null) {
@@ -307,19 +313,19 @@
* Returns the maximum allowed width for bitmaps drawn with this canvas.
* Attempting to draw with a bitmap wider than this value will result
* in an error.
- *
- * @see #getMaximumBitmapHeight()
+ *
+ * @see #getMaximumBitmapHeight()
*/
public int getMaximumBitmapWidth() {
return MAXMIMUM_BITMAP_SIZE;
}
-
+
/**
* Returns the maximum allowed height for bitmaps drawn with this canvas.
* Attempting to draw with a bitmap taller than this value will result
* in an error.
- *
- * @see #getMaximumBitmapWidth()
+ *
+ * @see #getMaximumBitmapWidth()
*/
public int getMaximumBitmapHeight() {
return MAXMIMUM_BITMAP_SIZE;
@@ -327,6 +333,19 @@
// the SAVE_FLAG constants must match their native equivalents
+ /** @hide */
+ @IntDef(flag = true,
+ value = {
+ MATRIX_SAVE_FLAG,
+ CLIP_SAVE_FLAG,
+ HAS_ALPHA_LAYER_SAVE_FLAG,
+ FULL_COLOR_LAYER_SAVE_FLAG,
+ CLIP_TO_LAYER_SAVE_FLAG,
+ ALL_SAVE_FLAG
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Saveflags {}
+
/** restore the current matrix when restore() is called */
public static final int MATRIX_SAVE_FLAG = 0x01;
/** restore the current clip when restore() is called */
@@ -338,8 +357,8 @@
/** clip against the layer's bounds */
public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10;
/** restore everything when restore() is called */
- public static final int ALL_SAVE_FLAG = 0x1F;
-
+ public static final int ALL_SAVE_FLAG = 0x1F;
+
/**
* Saves the current matrix and clip onto a private stack. Subsequent
* calls to translate,scale,rotate,skew,concat or clipRect,clipPath
@@ -352,7 +371,7 @@
public int save() {
return native_save(mNativeCanvasWrapper, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
}
-
+
/**
* Based on saveFlags, can save the current matrix and clip onto a private
* stack. Subsequent calls to translate,scale,rotate,skew,concat or
@@ -364,7 +383,7 @@
* to save/restore
* @return The value to pass to restoreToCount() to balance this save()
*/
- public int save(int saveFlags) {
+ public int save(@Saveflags int saveFlags) {
return native_save(mNativeCanvasWrapper, saveFlags);
}
@@ -384,7 +403,7 @@
* @param saveFlags see _SAVE_FLAG constants
* @return value to pass to restoreToCount() to balance this save()
*/
- public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
+ public int saveLayer(@Nullable RectF bounds, @Nullable Paint paint, @Saveflags int saveFlags) {
return native_saveLayer(mNativeCanvasWrapper,
bounds.left, bounds.top, bounds.right, bounds.bottom,
paint != null ? paint.mNativePaint : 0,
@@ -394,15 +413,15 @@
/**
* Convenience for saveLayer(bounds, paint, {@link #ALL_SAVE_FLAG})
*/
- public int saveLayer(RectF bounds, Paint paint) {
+ public int saveLayer(@Nullable RectF bounds, @Nullable Paint paint) {
return saveLayer(bounds, paint, ALL_SAVE_FLAG);
}
/**
* Helper version of saveLayer() that takes 4 values rather than a RectF.
*/
- public int saveLayer(float left, float top, float right, float bottom, Paint paint,
- int saveFlags) {
+ public int saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint,
+ @Saveflags int saveFlags) {
return native_saveLayer(mNativeCanvasWrapper, left, top, right, bottom,
paint != null ? paint.mNativePaint : 0,
saveFlags);
@@ -411,7 +430,7 @@
/**
* Convenience for saveLayer(left, top, right, bottom, paint, {@link #ALL_SAVE_FLAG})
*/
- public int saveLayer(float left, float top, float right, float bottom, Paint paint) {
+ public int saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint) {
return saveLayer(left, top, right, bottom, paint, ALL_SAVE_FLAG);
}
@@ -431,7 +450,7 @@
* @param saveFlags see _SAVE_FLAG constants
* @return value to pass to restoreToCount() to balance this call
*/
- public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
+ public int saveLayerAlpha(@NonNull RectF bounds, int alpha, @Saveflags int saveFlags) {
alpha = Math.min(255, Math.max(0, alpha));
return native_saveLayerAlpha(mNativeCanvasWrapper,
bounds.left, bounds.top, bounds.right, bounds.bottom,
@@ -441,7 +460,7 @@
/**
* Convenience for saveLayerAlpha(bounds, alpha, {@link #ALL_SAVE_FLAG})
*/
- public int saveLayerAlpha(RectF bounds, int alpha) {
+ public int saveLayerAlpha(@NonNull RectF bounds, int alpha) {
return saveLayerAlpha(bounds, alpha, ALL_SAVE_FLAG);
}
@@ -449,7 +468,7 @@
* Helper for saveLayerAlpha() that takes 4 values instead of a RectF.
*/
public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
- int saveFlags) {
+ @Saveflags int saveFlags) {
return native_saveLayerAlpha(mNativeCanvasWrapper, left, top, right, bottom,
alpha, saveFlags);
}
@@ -567,34 +586,34 @@
*
* @param matrix The matrix to preconcatenate with the current matrix
*/
- public void concat(Matrix matrix) {
+ public void concat(@Nullable Matrix matrix) {
if (matrix != null) native_concat(mNativeCanvasWrapper, matrix.native_instance);
}
-
+
/**
* Completely replace the current matrix with the specified matrix. If the
* matrix parameter is null, then the current matrix is reset to identity.
- *
+ *
* <strong>Note:</strong> it is recommended to use {@link #concat(Matrix)},
* {@link #scale(float, float)}, {@link #translate(float, float)} and
* {@link #rotate(float)} instead of this method.
*
* @param matrix The matrix to replace the current matrix with. If it is
* null, set the current matrix to identity.
- *
- * @see #concat(Matrix)
+ *
+ * @see #concat(Matrix)
*/
- public void setMatrix(Matrix matrix) {
+ public void setMatrix(@Nullable Matrix matrix) {
native_setMatrix(mNativeCanvasWrapper,
matrix == null ? 0 : matrix.native_instance);
}
-
+
/**
* Return, in ctm, the current transformation matrix. This does not alter
* the matrix in the canvas, but just returns a copy of it.
*/
@Deprecated
- public void getMatrix(Matrix ctm) {
+ public void getMatrix(@NonNull Matrix ctm) {
native_getCTM(mNativeCanvasWrapper, ctm.native_instance);
}
@@ -603,13 +622,13 @@
* matrix.
*/
@Deprecated
- public final Matrix getMatrix() {
+ public final @NonNull Matrix getMatrix() {
Matrix m = new Matrix();
//noinspection deprecation
getMatrix(m);
return m;
}
-
+
/**
* Modify the current clip with the specified rectangle.
*
@@ -617,7 +636,7 @@
* @param op How the clip is modified
* @return true if the resulting clip is non-empty
*/
- public boolean clipRect(RectF rect, Region.Op op) {
+ public boolean clipRect(@NonNull RectF rect, @NonNull Region.Op op) {
return native_clipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom,
op.nativeInt);
}
@@ -630,7 +649,7 @@
* @param op How the clip is modified
* @return true if the resulting clip is non-empty
*/
- public boolean clipRect(Rect rect, Region.Op op) {
+ public boolean clipRect(@NonNull Rect rect, @NonNull Region.Op op) {
return native_clipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom,
op.nativeInt);
}
@@ -642,7 +661,7 @@
* @param rect The rectangle to intersect with the current clip.
* @return true if the resulting clip is non-empty
*/
- public boolean clipRect(RectF rect) {
+ public boolean clipRect(@NonNull RectF rect) {
return native_clipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom,
Region.Op.INTERSECT.nativeInt);
}
@@ -654,11 +673,11 @@
* @param rect The rectangle to intersect with the current clip.
* @return true if the resulting clip is non-empty
*/
- public boolean clipRect(Rect rect) {
+ public boolean clipRect(@NonNull Rect rect) {
return native_clipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom,
Region.Op.INTERSECT.nativeInt);
}
-
+
/**
* Modify the current clip with the specified rectangle, which is
* expressed in local coordinates.
@@ -674,7 +693,8 @@
* @param op How the clip is modified
* @return true if the resulting clip is non-empty
*/
- public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
+ public boolean clipRect(float left, float top, float right, float bottom,
+ @NonNull Region.Op op) {
return native_clipRect(mNativeCanvasWrapper, left, top, right, bottom, op.nativeInt);
}
@@ -721,20 +741,20 @@
* @param op How the clip is modified
* @return true if the resulting is non-empty
*/
- public boolean clipPath(Path path, Region.Op op) {
+ public boolean clipPath(@NonNull Path path, @NonNull Region.Op op) {
return native_clipPath(mNativeCanvasWrapper, path.ni(), op.nativeInt);
}
-
+
/**
* Intersect the current clip with the specified path.
*
* @param path The path to intersect with the current clip
* @return true if the resulting is non-empty
*/
- public boolean clipPath(Path path) {
+ public boolean clipPath(@NonNull Path path) {
return clipPath(path, Region.Op.INTERSECT);
}
-
+
/**
* Modify the current clip with the specified region. Note that unlike
* clipRect() and clipPath() which transform their arguments by the
@@ -749,7 +769,7 @@
* @deprecated Unlike all other clip calls this API does not respect the
* current matrix. Use {@link #clipRect(Rect)} as an alternative.
*/
- public boolean clipRegion(Region region, Region.Op op) {
+ public boolean clipRegion(@NonNull Region region, @NonNull Region.Op op) {
return native_clipRegion(mNativeCanvasWrapper, region.ni(), op.nativeInt);
}
@@ -766,15 +786,15 @@
* @deprecated Unlike all other clip calls this API does not respect the
* current matrix. Use {@link #clipRect(Rect)} as an alternative.
*/
- public boolean clipRegion(Region region) {
+ public boolean clipRegion(@NonNull Region region) {
return clipRegion(region, Region.Op.INTERSECT);
}
-
- public DrawFilter getDrawFilter() {
+
+ public @Nullable DrawFilter getDrawFilter() {
return mDrawFilter;
}
-
- public void setDrawFilter(DrawFilter filter) {
+
+ public void setDrawFilter(@Nullable DrawFilter filter) {
long nativeFilter = 0;
if (filter != null) {
nativeFilter = filter.mNativeInt;
@@ -794,7 +814,7 @@
* Antialiased: Treat edges by rounding-out, since they may be antialiased
*/
AA(1);
-
+
EdgeType(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -818,7 +838,7 @@
* @return true if the rect (transformed by the canvas' matrix)
* does not intersect with the canvas' clip
*/
- public boolean quickReject(RectF rect, EdgeType type) {
+ public boolean quickReject(@NonNull RectF rect, @NonNull EdgeType type) {
return native_quickReject(mNativeCanvasWrapper,
rect.left, rect.top, rect.right, rect.bottom);
}
@@ -838,7 +858,7 @@
* @return true if the path (transformed by the canvas' matrix)
* does not intersect with the canvas' clip
*/
- public boolean quickReject(Path path, EdgeType type) {
+ public boolean quickReject(@NonNull Path path, @NonNull EdgeType type) {
return native_quickReject(mNativeCanvasWrapper, path.ni());
}
@@ -863,7 +883,7 @@
* does not intersect with the canvas' clip
*/
public boolean quickReject(float left, float top, float right, float bottom,
- EdgeType type) {
+ @NonNull EdgeType type) {
return native_quickReject(mNativeCanvasWrapper, left, top, right, bottom);
}
@@ -877,21 +897,21 @@
* still return true if the current clip is non-empty.
* @return true if the current clip is non-empty.
*/
- public boolean getClipBounds(Rect bounds) {
+ public boolean getClipBounds(@Nullable Rect bounds) {
return native_getClipBounds(mNativeCanvasWrapper, bounds);
}
-
+
/**
* Retrieve the bounds of the current clip (in local coordinates).
*
* @return the clip bounds, or [0, 0, 0, 0] if the clip is empty.
*/
- public final Rect getClipBounds() {
+ public final @NonNull Rect getClipBounds() {
Rect r = new Rect();
getClipBounds(r);
return r;
}
-
+
/**
* Fill the entire canvas' bitmap (restricted to the current clip) with the
* specified RGB color, using srcover porterduff mode.
@@ -934,7 +954,7 @@
* @param color the color to draw with
* @param mode the porter-duff mode to apply to the color
*/
- public void drawColor(int color, PorterDuff.Mode mode) {
+ public void drawColor(int color, @NonNull PorterDuff.Mode mode) {
native_drawColor(mNativeCanvasWrapper, color, mode.nativeInt);
}
@@ -945,10 +965,10 @@
*
* @param paint The paint used to draw onto the canvas
*/
- public void drawPaint(Paint paint) {
+ public void drawPaint(@NonNull Paint paint) {
native_drawPaint(mNativeCanvasWrapper, paint.mNativePaint);
}
-
+
/**
* Draw a series of points. Each point is centered at the coordinate
* specified by pts[], and its diameter is specified by the paint's stroke
@@ -965,21 +985,21 @@
* "points" that are drawn is really (count >> 1).
* @param paint The paint used to draw the points
*/
- public void drawPoints(float[] pts, int offset, int count, Paint paint) {
+ public void drawPoints(float[] pts, int offset, int count, @NonNull Paint paint) {
native_drawPoints(mNativeCanvasWrapper, pts, offset, count, paint.mNativePaint);
}
/**
* Helper for drawPoints() that assumes you want to draw the entire array
*/
- public void drawPoints(float[] pts, Paint paint) {
+ public void drawPoints(@NonNull float[] pts, @NonNull Paint paint) {
drawPoints(pts, 0, pts.length, paint);
}
/**
* Helper for drawPoints() for drawing a single point.
*/
- public void drawPoint(float x, float y, Paint paint) {
+ public void drawPoint(float x, float y, @NonNull Paint paint) {
native_drawPoint(mNativeCanvasWrapper, x, y, paint.mNativePaint);
}
@@ -995,7 +1015,8 @@
* @param startY The y-coordinate of the start point of the line
* @param paint The paint used to draw the line
*/
- public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
+ public void drawLine(float startX, float startY, float stopX, float stopY,
+ @NonNull Paint paint) {
native_drawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.mNativePaint);
}
@@ -1018,7 +1039,7 @@
native_drawLines(mNativeCanvasWrapper, pts, offset, count, paint.mNativePaint);
}
- public void drawLines(float[] pts, Paint paint) {
+ public void drawLines(@NonNull float[] pts, @NonNull Paint paint) {
drawLines(pts, 0, pts.length, paint);
}
@@ -1029,7 +1050,7 @@
* @param rect The rect to be drawn
* @param paint The paint used to draw the rect
*/
- public void drawRect(RectF rect, Paint paint) {
+ public void drawRect(@NonNull RectF rect, @NonNull Paint paint) {
native_drawRect(mNativeCanvasWrapper,
rect.left, rect.top, rect.right, rect.bottom, paint.mNativePaint);
}
@@ -1041,10 +1062,10 @@
* @param r The rectangle to be drawn.
* @param paint The paint used to draw the rectangle
*/
- public void drawRect(Rect r, Paint paint) {
+ public void drawRect(@NonNull Rect r, @NonNull Paint paint) {
drawRect(r.left, r.top, r.right, r.bottom, paint);
}
-
+
/**
* Draw the specified Rect using the specified paint. The rectangle will
@@ -1056,7 +1077,7 @@
* @param bottom The bottom side of the rectangle to be drawn
* @param paint The paint used to draw the rect
*/
- public void drawRect(float left, float top, float right, float bottom, Paint paint) {
+ public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) {
native_drawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.mNativePaint);
}
@@ -1066,11 +1087,19 @@
*
* @param oval The rectangle bounds of the oval to be drawn
*/
- public void drawOval(RectF oval, Paint paint) {
+ public void drawOval(@NonNull RectF oval, @NonNull Paint paint) {
if (oval == null) {
throw new NullPointerException();
}
- native_drawOval(mNativeCanvasWrapper, oval, paint.mNativePaint);
+ drawOval(oval.left, oval.top, oval.right, oval.bottom, paint);
+ }
+
+ /**
+ * Draw the specified oval using the specified paint. The oval will be
+ * filled or framed based on the Style in the paint.
+ */
+ public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) {
+ native_drawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.mNativePaint);
}
/**
@@ -1083,22 +1112,22 @@
* @param radius The radius of the cirle to be drawn
* @param paint The paint used to draw the circle
*/
- public void drawCircle(float cx, float cy, float radius, Paint paint) {
+ public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) {
native_drawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.mNativePaint);
}
/**
* <p>Draw the specified arc, which will be scaled to fit inside the
* specified oval.</p>
- *
+ *
* <p>If the start angle is negative or >= 360, the start angle is treated
* as start angle modulo 360.</p>
- *
+ *
* <p>If the sweep angle is >= 360, then the oval is drawn
* completely. Note that this differs slightly from SkPath::arcTo, which
* treats the sweep angle modulo 360. If the sweep angle is negative,
* the sweep angle is treated as sweep angle modulo 360</p>
- *
+ *
* <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the
* geometric angle of 0 degrees (3 o'clock on a watch.)</p>
*
@@ -1110,12 +1139,36 @@
close it if it is being stroked. This will draw a wedge
* @param paint The paint used to draw the arc
*/
- public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
- Paint paint) {
- if (oval == null) {
- throw new NullPointerException();
- }
- native_drawArc(mNativeCanvasWrapper, oval, startAngle, sweepAngle,
+ public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
+ @NonNull Paint paint) {
+ drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter,
+ paint);
+ }
+
+ /**
+ * <p>Draw the specified arc, which will be scaled to fit inside the
+ * specified oval.</p>
+ *
+ * <p>If the start angle is negative or >= 360, the start angle is treated
+ * as start angle modulo 360.</p>
+ *
+ * <p>If the sweep angle is >= 360, then the oval is drawn
+ * completely. Note that this differs slightly from SkPath::arcTo, which
+ * treats the sweep angle modulo 360. If the sweep angle is negative,
+ * the sweep angle is treated as sweep angle modulo 360</p>
+ *
+ * <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the
+ * geometric angle of 0 degrees (3 o'clock on a watch.)</p>
+ *
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise
+ * @param useCenter If true, include the center of the oval in the arc, and
+ close it if it is being stroked. This will draw a wedge
+ * @param paint The paint used to draw the arc
+ */
+ public void drawArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, boolean useCenter, @NonNull Paint paint) {
+ native_drawArc(mNativeCanvasWrapper, left, top, right, bottom, startAngle, sweepAngle,
useCenter, paint.mNativePaint);
}
@@ -1128,7 +1181,7 @@
* @param ry The y-radius of the oval used to round the corners
* @param paint The paint used to draw the roundRect
*/
- public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
+ public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) {
drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint);
}
@@ -1141,7 +1194,7 @@
* @param paint The paint used to draw the roundRect
*/
public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
- Paint paint) {
+ @NonNull Paint paint) {
native_drawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, paint.mNativePaint);
}
@@ -1152,7 +1205,7 @@
* @param path The path to be drawn
* @param paint The paint used to draw the path
*/
- public void drawPath(Path path, Paint paint) {
+ public void drawPath(@NonNull Path path, @NonNull Paint paint) {
native_drawPath(mNativeCanvasWrapper, path.ni(), paint.mNativePaint);
}
@@ -1176,10 +1229,10 @@
* @param patch The ninepatch object to render
* @param dst The destination rectangle.
* @param paint The paint to draw the bitmap with. may be null
- *
+ *
* @hide
*/
- public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
+ public void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint) {
patch.drawSoftware(this, dst, paint);
}
@@ -1192,14 +1245,14 @@
*
* @hide
*/
- public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
+ public void drawPatch(@NonNull NinePatch patch, @NonNull RectF dst, @Nullable Paint paint) {
patch.drawSoftware(this, dst, paint);
}
/**
* Draw the specified bitmap, with its top/left corner at (x,y), using
* the specified paint, transformed by the current matrix.
- *
+ *
* <p>Note: if the paint contains a maskfilter that generates a mask which
* extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
* then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
@@ -1209,13 +1262,13 @@
* <p>If the bitmap and canvas have different densities, this function
* will take care of automatically scaling the bitmap to draw at the
* same density as the canvas.
- *
+ *
* @param bitmap The bitmap to be drawn
* @param left The position of the left side of the bitmap being drawn
* @param top The position of the top side of the bitmap being drawn
* @param paint The paint used to draw the bitmap (may be null)
*/
- public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
+ public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
throwIfCannotDraw(bitmap);
native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top,
paint != null ? paint.mNativePaint : 0, mDensity, mScreenDensity, bitmap.mDensity);
@@ -1225,7 +1278,7 @@
* Draw the specified bitmap, scaling/translating automatically to fill
* the destination rectangle. If the source rectangle is not null, it
* specifies the subset of the bitmap to draw.
- *
+ *
* <p>Note: if the paint contains a maskfilter that generates a mask which
* extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
* then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
@@ -1236,14 +1289,15 @@
* This is because the source and destination rectangle coordinate
* spaces are in their respective densities, so must already have the
* appropriate scaling factor applied.
- *
+ *
* @param bitmap The bitmap to be drawn
* @param src May be null. The subset of the bitmap to be drawn
* @param dst The rectangle that the bitmap will be scaled/translated
* to fit into
* @param paint May be null. The paint used to draw the bitmap
*/
- public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
+ public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst,
+ @Nullable Paint paint) {
if (dst == null) {
throw new NullPointerException();
}
@@ -1256,7 +1310,7 @@
* Draw the specified bitmap, scaling/translating automatically to fill
* the destination rectangle. If the source rectangle is not null, it
* specifies the subset of the bitmap to draw.
- *
+ *
* <p>Note: if the paint contains a maskfilter that generates a mask which
* extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
* then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
@@ -1267,14 +1321,15 @@
* This is because the source and destination rectangle coordinate
* spaces are in their respective densities, so must already have the
* appropriate scaling factor applied.
- *
+ *
* @param bitmap The bitmap to be drawn
* @param src May be null. The subset of the bitmap to be drawn
* @param dst The rectangle that the bitmap will be scaled/translated
* to fit into
* @param paint May be null. The paint used to draw the bitmap
*/
- public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
+ public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst,
+ @Nullable Paint paint) {
if (dst == null) {
throw new NullPointerException();
}
@@ -1282,7 +1337,7 @@
native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), src, dst,
paint != null ? paint.mNativePaint : 0, mScreenDensity, bitmap.mDensity);
}
-
+
/**
* Treat the specified array of colors as a bitmap, and draw it. This gives
* the same result as first creating a bitmap from the array, and then
@@ -1308,8 +1363,8 @@
* and copies of pixel data.
*/
@Deprecated
- public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
- int width, int height, boolean hasAlpha, Paint paint) {
+ public void drawBitmap(@NonNull int[] colors, int offset, int stride, float x, float y,
+ int width, int height, boolean hasAlpha, @Nullable Paint paint) {
// check for valid input
if (width < 0) {
throw new IllegalArgumentException("width must be >= 0");
@@ -1344,8 +1399,8 @@
* and copies of pixel data.
*/
@Deprecated
- public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
- int width, int height, boolean hasAlpha, Paint paint) {
+ public void drawBitmap(@NonNull int[] colors, int offset, int stride, int x, int y,
+ int width, int height, boolean hasAlpha, @Nullable Paint paint) {
// call through to the common float version
drawBitmap(colors, offset, stride, (float)x, (float)y, width, height,
hasAlpha, paint);
@@ -1358,7 +1413,7 @@
* @param matrix The matrix used to transform the bitmap when it is drawn
* @param paint May be null. The paint used to draw the bitmap
*/
- public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
+ public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.ni(), matrix.ni(),
paint != null ? paint.mNativePaint : 0);
}
@@ -1371,7 +1426,7 @@
throw new ArrayIndexOutOfBoundsException();
}
}
-
+
/**
* Draw the bitmap through the mesh, where mesh vertices are evenly
* distributed across the bitmap. There are meshWidth+1 vertices across, and
@@ -1398,8 +1453,9 @@
* @param colorOffset Number of color elements to skip before drawing
* @param paint May be null. The paint used to draw the bitmap
*/
- public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight,
- float[] verts, int vertOffset, int[] colors, int colorOffset, Paint paint) {
+ public void drawBitmapMesh(@NonNull Bitmap bitmap, int meshWidth, int meshHeight,
+ @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset,
+ @Nullable Paint paint) {
if ((meshWidth | meshHeight | vertOffset | colorOffset) < 0) {
throw new ArrayIndexOutOfBoundsException();
}
@@ -1422,7 +1478,7 @@
TRIANGLES(0),
TRIANGLE_STRIP(1),
TRIANGLE_FAN(2);
-
+
VertexMode(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -1432,7 +1488,7 @@
*/
public final int nativeInt;
}
-
+
/**
* Draw the array of vertices, interpreted as triangles (based on mode). The
* verts array is required, and specifies the x,y pairs for each vertex. If
@@ -1461,11 +1517,12 @@
* @param indices If not null, array of indices to reference into the
* vertex (texs, colors) array.
* @param indexCount number of entries in the indices array (if not null).
- * @param paint Specifies the shader to use if the texs array is non-null.
+ * @param paint Specifies the shader to use if the texs array is non-null.
*/
- public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
- float[] texs, int texOffset, int[] colors, int colorOffset,
- short[] indices, int indexOffset, int indexCount, Paint paint) {
+ public void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts,
+ int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors,
+ int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount,
+ @NonNull Paint paint) {
checkRange(verts.length, vertOffset, vertexCount);
if (texs != null) {
checkRange(texs.length, texOffset, vertexCount);
@@ -1490,7 +1547,8 @@
* @param y The y-coordinate of the origin of the text being drawn
* @param paint The paint used for the text (e.g. color, size, style)
*/
- public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
+ public void drawText(@NonNull char[] text, int index, int count, float x, float y,
+ @NonNull Paint paint) {
if ((index | count | (index + count) |
(text.length - index - count)) < 0) {
throw new IndexOutOfBoundsException();
@@ -1508,7 +1566,7 @@
* @param y The y-coordinate of the origin of the text being drawn
* @param paint The paint used for the text (e.g. color, size, style)
*/
- public void drawText(String text, float x, float y, Paint paint) {
+ public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
native_drawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags,
paint.mNativePaint, paint.mNativeTypeface);
}
@@ -1524,7 +1582,8 @@
* @param y The y-coordinate of the origin of the text being drawn
* @param paint The paint used for the text (e.g. color, size, style)
*/
- public void drawText(String text, int start, int end, float x, float y, Paint paint) {
+ public void drawText(@NonNull String text, int start, int end, float x, float y,
+ @NonNull Paint paint) {
if ((start | end | (end - start) | (text.length() - end)) < 0) {
throw new IndexOutOfBoundsException();
}
@@ -1545,7 +1604,8 @@
* @param y The y-coordinate of origin for where to draw the text
* @param paint The paint used for the text (e.g. color, size, style)
*/
- public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
+ public void drawText(@NonNull CharSequence text, int start, int end, float x, float y,
+ @NonNull Paint paint) {
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
native_drawText(mNativeCanvasWrapper, text.toString(), start, end, x, y,
@@ -1567,7 +1627,7 @@
* bidi on the provided text, but renders it as a uniform right-to-left or
* left-to-right run, as indicated by dir. Alignment of the text is as
* determined by the Paint's TextAlign value.
- *
+ *
* @param text the text to render
* @param index the start of the text to render
* @param count the count of chars to render
@@ -1578,13 +1638,12 @@
* + count.
* @param x the x position at which to draw the text
* @param y the y position at which to draw the text
- * @param dir the run direction, either {@link #DIRECTION_LTR} or
- * {@link #DIRECTION_RTL}.
+ * @param isRtl whether the run is in RTL direction
* @param paint the paint
* @hide
*/
- public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
- float x, float y, int dir, Paint paint) {
+ public void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex,
+ int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint) {
if (text == null) {
throw new NullPointerException("text is null");
@@ -1595,12 +1654,9 @@
if ((index | count | text.length - index - count) < 0) {
throw new IndexOutOfBoundsException();
}
- if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
- throw new IllegalArgumentException("unknown dir: " + dir);
- }
native_drawTextRun(mNativeCanvasWrapper, text, index, count,
- contextIndex, contextCount, x, y, dir, paint.mNativePaint, paint.mNativeTypeface);
+ contextIndex, contextCount, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
}
/**
@@ -1616,12 +1672,12 @@
* position can be used for shaping context.
* @param x the x position at which to draw the text
* @param y the y position at which to draw the text
- * @param dir the run direction, either 0 for LTR or 1 for RTL.
+ * @param isRtl whether the run is in RTL direction
* @param paint the paint
* @hide
*/
- public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
- float x, float y, int dir, Paint paint) {
+ public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart,
+ int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) {
if (text == null) {
throw new NullPointerException("text is null");
@@ -1633,22 +1689,20 @@
throw new IndexOutOfBoundsException();
}
- int flags = dir == 0 ? 0 : 1;
-
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
native_drawTextRun(mNativeCanvasWrapper, text.toString(), start, end,
- contextStart, contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
+ contextStart, contextEnd, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawTextRun(this, start, end,
- contextStart, contextEnd, x, y, flags, paint);
+ contextStart, contextEnd, x, y, isRtl, paint);
} else {
int contextLen = contextEnd - contextStart;
int len = end - start;
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
native_drawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len,
- 0, contextLen, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
+ 0, contextLen, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
TemporaryBuffer.recycle(buf);
}
}
@@ -1656,7 +1710,7 @@
/**
* Draw the text in the array, with each character's origin specified by
* the pos array.
- *
+ *
* This method does not support glyph composition and decomposition and
* should therefore not be used to render complex scripts.
*
@@ -1668,7 +1722,8 @@
* @param paint The paint used for the text (e.g. color, size, style)
*/
@Deprecated
- public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
+ public void drawPosText(@NonNull char[] text, int index, int count, @NonNull float[] pos,
+ @NonNull Paint paint) {
if (index < 0 || index + count > text.length || count*2 > pos.length) {
throw new IndexOutOfBoundsException();
}
@@ -1679,7 +1734,7 @@
/**
* Draw the text in the array, with each character's origin specified by
* the pos array.
- *
+ *
* This method does not support glyph composition and decomposition and
* should therefore not be used to render complex scripts.
*
@@ -1688,7 +1743,7 @@
* @param paint The paint used for the text (e.g. color, size, style)
*/
@Deprecated
- public void drawPosText(String text, float[] pos, Paint paint) {
+ public void drawPosText(@NonNull String text, @NonNull float[] pos, @NonNull Paint paint) {
if (text.length()*2 > pos.length) {
throw new ArrayIndexOutOfBoundsException();
}
@@ -1708,8 +1763,8 @@
* the text
* @param paint The paint used for the text (e.g. color, size, style)
*/
- public void drawTextOnPath(char[] text, int index, int count, Path path,
- float hOffset, float vOffset, Paint paint) {
+ public void drawTextOnPath(@NonNull char[] text, int index, int count, @NonNull Path path,
+ float hOffset, float vOffset, @NonNull Paint paint) {
if (index < 0 || index + count > text.length) {
throw new ArrayIndexOutOfBoundsException();
}
@@ -1731,7 +1786,8 @@
* the text
* @param paint The paint used for the text (e.g. color, size, style)
*/
- public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
+ public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset,
+ float vOffset, @NonNull Paint paint) {
if (text.length() > 0) {
native_drawTextOnPath(mNativeCanvasWrapper, text, path.ni(), hOffset, vOffset,
paint.mBidiFlags, paint.mNativePaint);
@@ -1746,20 +1802,20 @@
* <p>
* <strong>Note:</strong> This forces the picture to internally call
* {@link Picture#endRecording} in order to prepare for playback.
- *
+ *
* @param picture The picture to be drawn
*/
- public void drawPicture(Picture picture) {
+ public void drawPicture(@NonNull Picture picture) {
picture.endRecording();
int restoreCount = save();
picture.draw(this);
restoreToCount(restoreCount);
}
-
+
/**
* Draw the picture, stretched to fit into the dst rectangle.
*/
- public void drawPicture(Picture picture, RectF dst) {
+ public void drawPicture(@NonNull Picture picture, @NonNull RectF dst) {
save();
translate(dst.left, dst.top);
if (picture.getWidth() > 0 && picture.getHeight() > 0) {
@@ -1768,11 +1824,11 @@
drawPicture(picture);
restore();
}
-
+
/**
* Draw the picture, stretched to fit into the dst rectangle.
*/
- public void drawPicture(Picture picture, Rect dst) {
+ public void drawPicture(@NonNull Picture picture, @NonNull Rect dst) {
save();
translate(dst.left, dst.top);
if (picture.getWidth() > 0 && picture.getHeight() > 0) {
@@ -1884,14 +1940,14 @@
float top, float right,
float bottom,
long nativePaint);
- private static native void native_drawOval(long nativeCanvas, RectF oval,
- long nativePaint);
+ private static native void native_drawOval(long nativeCanvas, float left, float top,
+ float right, float bottom, long nativePaint);
private static native void native_drawCircle(long nativeCanvas, float cx,
float cy, float radius,
long nativePaint);
- private static native void native_drawArc(long nativeCanvas, RectF oval,
- float startAngle, float sweep,
- boolean useCenter,
+ private static native void native_drawArc(long nativeCanvas, float left, float top,
+ float right, float bottom,
+ float startAngle, float sweep, boolean useCenter,
long nativePaint);
private static native void native_drawRoundRect(long nativeCanvas,
float left, float top, float right, float bottom,
@@ -1947,11 +2003,11 @@
private static native void native_drawTextRun(long nativeCanvas, String text,
int start, int end, int contextStart, int contextEnd,
- float x, float y, int flags, long nativePaint, long nativeTypeface);
+ float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
private static native void native_drawTextRun(long nativeCanvas, char[] text,
int start, int count, int contextStart, int contextCount,
- float x, float y, int flags, long nativePaint, long nativeTypeface);
+ float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
private static native void native_drawPosText(long nativeCanvas,
char[] text, int index,
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 4268a24..17ce026 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -56,7 +56,7 @@
* @hide
*/
public int mBidiFlags = BIDI_DEFAULT_LTR;
-
+
static final Style[] sStyleArray = {
Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
};
@@ -202,14 +202,14 @@
/**
* Bidi flag to set LTR paragraph direction.
- *
+ *
* @hide
*/
public static final int BIDI_LTR = 0x0;
/**
* Bidi flag to set RTL paragraph direction.
- *
+ *
* @hide
*/
public static final int BIDI_RTL = 0x1;
@@ -217,7 +217,7 @@
/**
* Bidi flag to detect paragraph direction via heuristics, defaulting to
* LTR.
- *
+ *
* @hide
*/
public static final int BIDI_DEFAULT_LTR = 0x2;
@@ -225,21 +225,21 @@
/**
* Bidi flag to detect paragraph direction via heuristics, defaulting to
* RTL.
- *
+ *
* @hide
*/
public static final int BIDI_DEFAULT_RTL = 0x3;
/**
* Bidi flag to override direction to all LTR (ignore bidi).
- *
+ *
* @hide
*/
public static final int BIDI_FORCE_LTR = 0x4;
/**
* Bidi flag to override direction to all RTL (ignore bidi).
- *
+ *
* @hide
*/
public static final int BIDI_FORCE_RTL = 0x5;
@@ -331,7 +331,7 @@
* either FILL or STROKE.
*/
FILL_AND_STROKE (2);
-
+
Style(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -357,7 +357,7 @@
* of the path.
*/
SQUARE (2);
-
+
private Cap(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -381,7 +381,7 @@
* The outer edges of a join meet with a straight line
*/
BEVEL (2);
-
+
private Join(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -405,7 +405,7 @@
* The text is drawn to the left of the x,y origin
*/
RIGHT (2);
-
+
private Align(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -418,7 +418,7 @@
public Paint() {
this(0);
}
-
+
/**
* Create a new paint with the specified flags. Use setFlags() to change
* these after the paint is created.
@@ -475,7 +475,7 @@
setTextLocale(Locale.getDefault());
setElegantTextHeight(false);
}
-
+
/**
* Copy the fields from src into this paint. This is equivalent to calling
* get() on all of the src fields, and calling the corresponding set()
@@ -529,7 +529,7 @@
/**
* Return the bidi flags on the paint.
- *
+ *
* @return the bidi flags on the paint
* @hide
*/
@@ -552,7 +552,7 @@
/**
* Return the paint's flags. Use the Flag enum to test flag values.
- *
+ *
* @return the paint's flags (see enums ending in _Flag for bit masks)
*/
public native int getFlags();
@@ -587,7 +587,7 @@
public final boolean isAntiAlias() {
return (getFlags() & ANTI_ALIAS_FLAG) != 0;
}
-
+
/**
* Helper for setFlags(), setting or clearing the ANTI_ALIAS_FLAG bit
* AntiAliasing smooths out the edges of what is being drawn, but is has
@@ -597,7 +597,7 @@
* @param aa true to set the antialias bit in the flags, false to clear it
*/
public native void setAntiAlias(boolean aa);
-
+
/**
* Helper for getFlags(), returning true if DITHER_FLAG bit is set
* Dithering affects how colors that are higher precision than the device
@@ -611,7 +611,7 @@
public final boolean isDither() {
return (getFlags() & DITHER_FLAG) != 0;
}
-
+
/**
* Helper for setFlags(), setting or clearing the DITHER_FLAG bit
* Dithering affects how colors that are higher precision than the device
@@ -623,7 +623,7 @@
* @param dither true to set the dithering bit in flags, false to clear it
*/
public native void setDither(boolean dither);
-
+
/**
* Helper for getFlags(), returning true if LINEAR_TEXT_FLAG bit is set
*
@@ -649,7 +649,7 @@
public final boolean isSubpixelText() {
return (getFlags() & SUBPIXEL_TEXT_FLAG) != 0;
}
-
+
/**
* Helper for setFlags(), setting or clearing the SUBPIXEL_TEXT_FLAG bit
*
@@ -657,7 +657,7 @@
* flags, false to clear it.
*/
public native void setSubpixelText(boolean subpixelText);
-
+
/**
* Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set
*
@@ -708,7 +708,7 @@
* flags, false to clear it.
*/
public native void setFakeBoldText(boolean fakeBoldText);
-
+
/**
* Whether or not the bitmap filter is activated.
* Filtering affects the sampling of bitmaps when they are transformed.
@@ -720,13 +720,13 @@
public final boolean isFilterBitmap() {
return (getFlags() & FILTER_BITMAP_FLAG) != 0;
}
-
+
/**
* Helper for setFlags(), setting or clearing the FILTER_BITMAP_FLAG bit.
* Filtering affects the sampling of bitmaps when they are transformed.
* Filtering does not affect how the colors in the bitmap are converted into
* device pixels. That is dependent on dithering and xfermodes.
- *
+ *
* @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's
* flags, false to clear it.
*/
@@ -773,7 +773,7 @@
* @param color The new color (including alpha) to set in the paint.
*/
public native void setColor(int color);
-
+
/**
* Helper to getColor() that just returns the color's alpha value. This is
* the same as calling getColor() >>> 24. It always returns a value between
@@ -1285,7 +1285,7 @@
*/
public static class FontMetrics {
/**
- * The maximum distance above the baseline for the tallest glyph in
+ * The maximum distance above the baseline for the tallest glyph in
* the font at a given text size.
*/
public float top;
@@ -1298,7 +1298,7 @@
*/
public float descent;
/**
- * The maximum distance below the baseline for the lowest glyph in
+ * The maximum distance below the baseline for the lowest glyph in
* the font at a given text size.
*/
public float bottom;
@@ -1307,7 +1307,7 @@
*/
public float leading;
}
-
+
/**
* Return the font's recommended interline spacing, given the Paint's
* settings for typeface, textSize, etc. If metrics is not null, return the
@@ -1318,7 +1318,7 @@
* @return the font's recommended interline spacing.
*/
public native float getFontMetrics(FontMetrics metrics);
-
+
/**
* Allocates a new FontMetrics object, and then calls getFontMetrics(fm)
* with it, returning the object.
@@ -1328,7 +1328,7 @@
getFontMetrics(fm);
return fm;
}
-
+
/**
* Convenience method for callers that want to have FontMetrics values as
* integers.
@@ -1339,7 +1339,7 @@
public int descent;
public int bottom;
public int leading;
-
+
@Override public String toString() {
return "FontMetricsInt: top=" + top + " ascent=" + ascent +
" descent=" + descent + " bottom=" + bottom +
@@ -1364,7 +1364,7 @@
getFontMetricsInt(fm);
return fm;
}
-
+
/**
* Return the recommend line spacing based on the current typeface and
* text size.
@@ -1407,7 +1407,7 @@
}
private native float native_measureText(char[] text, int index, int count, int bidiFlags);
-
+
/**
* Return the width of the text.
*
@@ -1439,7 +1439,7 @@
}
private native float native_measureText(String text, int start, int end, int bidiFlags);
-
+
/**
* Return the width of the text.
*
@@ -1466,7 +1466,7 @@
}
private native float native_measureText(String text, int bidiFlags);
-
+
/**
* Return the width of the text.
*
@@ -1503,7 +1503,7 @@
TemporaryBuffer.recycle(buf);
return result;
}
-
+
/**
* Measure the text, stopping early if the measured width exceeds maxWidth.
* Return the number of chars that were measured, and if measuredWidth is
@@ -1532,20 +1532,22 @@
return 0;
}
if (!mHasCompatScaling) {
- return native_breakText(text, index, count, maxWidth, mBidiFlags, measuredWidth);
+ return native_breakText(mNativePaint, mNativeTypeface, text, index, count, maxWidth,
+ mBidiFlags, measuredWidth);
}
final float oldSize = getTextSize();
- setTextSize(oldSize*mCompatScaling);
- int res = native_breakText(text, index, count, maxWidth*mCompatScaling, mBidiFlags,
- measuredWidth);
+ setTextSize(oldSize * mCompatScaling);
+ int res = native_breakText(mNativePaint, mNativeTypeface, text, index, count,
+ maxWidth * mCompatScaling, mBidiFlags, measuredWidth);
setTextSize(oldSize);
if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
return res;
}
- private native int native_breakText(char[] text, int index, int count,
- float maxWidth, int bidiFlags, float[] measuredWidth);
+ private static native int native_breakText(long native_object, long native_typeface,
+ char[] text, int index, int count,
+ float maxWidth, int bidiFlags, float[] measuredWidth);
/**
* Measure the text, stopping early if the measured width exceeds maxWidth.
@@ -1622,19 +1624,21 @@
return 0;
}
if (!mHasCompatScaling) {
- return native_breakText(text, measureForwards, maxWidth, mBidiFlags, measuredWidth);
+ return native_breakText(mNativePaint, mNativeTypeface, text, measureForwards,
+ maxWidth, mBidiFlags, measuredWidth);
}
final float oldSize = getTextSize();
setTextSize(oldSize*mCompatScaling);
- int res = native_breakText(text, measureForwards, maxWidth*mCompatScaling, mBidiFlags,
- measuredWidth);
+ int res = native_breakText(mNativePaint, mNativeTypeface, text, measureForwards,
+ maxWidth*mCompatScaling, mBidiFlags, measuredWidth);
setTextSize(oldSize);
if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
return res;
}
- private native int native_breakText(String text, boolean measureForwards,
+ private static native int native_breakText(long native_object, long native_typeface,
+ String text, boolean measureForwards,
float maxWidth, int bidiFlags, float[] measuredWidth);
/**
@@ -1738,7 +1742,7 @@
if (end - start > widths.length) {
throw new ArrayIndexOutOfBoundsException();
}
-
+
if (text.length() == 0 || start == end) {
return 0;
}
@@ -1755,7 +1759,7 @@
}
return res;
}
-
+
/**
* Return the advance widths for the characters in the string.
*
@@ -1816,15 +1820,12 @@
* @hide
*/
public float getTextRunAdvances(char[] chars, int index, int count,
- int contextIndex, int contextCount, int flags, float[] advances,
+ int contextIndex, int contextCount, boolean isRtl, float[] advances,
int advancesIndex) {
if (chars == null) {
throw new IllegalArgumentException("text cannot be null");
}
- if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
- throw new IllegalArgumentException("unknown flags value: " + flags);
- }
if ((index | count | contextIndex | contextCount | advancesIndex
| (index - contextIndex) | (contextCount - count)
| ((contextIndex + contextCount) - (index + count))
@@ -1839,13 +1840,13 @@
}
if (!mHasCompatScaling) {
return native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
- contextIndex, contextCount, flags, advances, advancesIndex);
+ contextIndex, contextCount, isRtl, advances, advancesIndex);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
float res = native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
- contextIndex, contextCount, flags, advances, advancesIndex);
+ contextIndex, contextCount, isRtl, advances, advancesIndex);
setTextSize(oldSize);
if (advances != null) {
@@ -1864,7 +1865,7 @@
* @hide
*/
public float getTextRunAdvances(CharSequence text, int start, int end,
- int contextStart, int contextEnd, int flags, float[] advances,
+ int contextStart, int contextEnd, boolean isRtl, float[] advances,
int advancesIndex) {
if (text == null) {
@@ -1880,16 +1881,16 @@
if (text instanceof String) {
return getTextRunAdvances((String) text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
+ contextStart, contextEnd, isRtl, advances, advancesIndex);
}
if (text instanceof SpannedString ||
text instanceof SpannableString) {
return getTextRunAdvances(text.toString(), start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
+ contextStart, contextEnd, isRtl, advances, advancesIndex);
}
if (text instanceof GraphicsOperations) {
return ((GraphicsOperations) text).getTextRunAdvances(start, end,
- contextStart, contextEnd, flags, advances, advancesIndex, this);
+ contextStart, contextEnd, isRtl, advances, advancesIndex, this);
}
if (text.length() == 0 || end == start) {
return 0f;
@@ -1900,7 +1901,7 @@
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
float result = getTextRunAdvances(buf, start - contextStart, len,
- 0, contextLen, flags, advances, advancesIndex);
+ 0, contextLen, isRtl, advances, advancesIndex);
TemporaryBuffer.recycle(buf);
return result;
}
@@ -1937,8 +1938,7 @@
* must be <= start
* @param contextEnd the index past the last character to use for shaping context,
* must be >= end
- * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
- * or {@link #DIRECTION_RTL}
+ * @param isRtl whether the run is in RTL direction
* @param advances array to receive the advances, must have room for all advances,
* can be null if only total advance is needed
* @param advancesIndex the position in advances at which to put the
@@ -1948,14 +1948,11 @@
* @hide
*/
public float getTextRunAdvances(String text, int start, int end, int contextStart,
- int contextEnd, int flags, float[] advances, int advancesIndex) {
+ int contextEnd, boolean isRtl, float[] advances, int advancesIndex) {
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
- if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
- throw new IllegalArgumentException("unknown flags value: " + flags);
- }
if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
| (start - contextStart) | (contextEnd - end)
| (text.length() - contextEnd)
@@ -1970,13 +1967,13 @@
if (!mHasCompatScaling) {
return native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
+ contextStart, contextEnd, isRtl, advances, advancesIndex);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
float totalAdvance = native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
+ contextStart, contextEnd, isRtl, advances, advancesIndex);
setTextSize(oldSize);
if (advances != null) {
@@ -2005,7 +2002,7 @@
* @param text the text
* @param contextStart the start of the context
* @param contextLength the length of the context
- * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
+ * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
* @param offset the cursor position to move from
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -2014,7 +2011,7 @@
* @hide
*/
public int getTextRunCursor(char[] text, int contextStart, int contextLength,
- int flags, int offset, int cursorOpt) {
+ int dir, int offset, int cursorOpt) {
int contextEnd = contextStart + contextLength;
if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
| (offset - contextStart) | (contextEnd - offset)
@@ -2024,7 +2021,7 @@
}
return native_getTextRunCursor(mNativePaint, text,
- contextStart, contextLength, flags, offset, cursorOpt);
+ contextStart, contextLength, dir, offset, cursorOpt);
}
/**
@@ -2045,7 +2042,7 @@
* @param text the text
* @param contextStart the start of the context
* @param contextEnd the end of the context
- * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
+ * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
* @param offset the cursor position to move from
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -2054,22 +2051,22 @@
* @hide
*/
public int getTextRunCursor(CharSequence text, int contextStart,
- int contextEnd, int flags, int offset, int cursorOpt) {
+ int contextEnd, int dir, int offset, int cursorOpt) {
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
return getTextRunCursor(text.toString(), contextStart, contextEnd,
- flags, offset, cursorOpt);
+ dir, offset, cursorOpt);
}
if (text instanceof GraphicsOperations) {
return ((GraphicsOperations) text).getTextRunCursor(
- contextStart, contextEnd, flags, offset, cursorOpt, this);
+ contextStart, contextEnd, dir, offset, cursorOpt, this);
}
int contextLen = contextEnd - contextStart;
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
- int result = getTextRunCursor(buf, 0, contextLen, flags, offset - contextStart, cursorOpt);
+ int result = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt);
TemporaryBuffer.recycle(buf);
return result;
}
@@ -2092,7 +2089,7 @@
* @param text the text
* @param contextStart the start of the context
* @param contextEnd the end of the context
- * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
+ * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
* @param offset the cursor position to move from
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -2101,7 +2098,7 @@
* @hide
*/
public int getTextRunCursor(String text, int contextStart, int contextEnd,
- int flags, int offset, int cursorOpt) {
+ int dir, int offset, int cursorOpt) {
if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
| (offset - contextStart) | (contextEnd - offset)
| (text.length() - contextEnd) | cursorOpt) < 0)
@@ -2110,7 +2107,7 @@
}
return native_getTextRunCursor(mNativePaint, text,
- contextStart, contextEnd, flags, offset, cursorOpt);
+ contextStart, contextEnd, dir, offset, cursorOpt);
}
/**
@@ -2156,7 +2153,7 @@
native_getTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, start, end, x, y,
path.ni());
}
-
+
/**
* Return in bounds (allocated by the caller) the smallest rectangle that
* encloses all of the characters, with an implied origin at (0,0).
@@ -2176,7 +2173,7 @@
}
nativeGetStringBounds(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, bounds);
}
-
+
/**
* Return in bounds (allocated by the caller) the smallest rectangle that
* encloses all of the characters, with an implied origin at (0,0).
@@ -2197,7 +2194,7 @@
nativeGetCharArrayBounds(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags,
bounds);
}
-
+
@Override
protected void finalize() throws Throwable {
try {
@@ -2252,15 +2249,15 @@
private static native float native_getTextRunAdvances(long native_object, long native_typeface,
char[] text, int index, int count, int contextIndex, int contextCount,
- int flags, float[] advances, int advancesIndex);
+ boolean isRtl, float[] advances, int advancesIndex);
private static native float native_getTextRunAdvances(long native_object, long native_typeface,
String text, int start, int end, int contextStart, int contextEnd,
- int flags, float[] advances, int advancesIndex);
+ boolean isRtl, float[] advances, int advancesIndex);
private native int native_getTextRunCursor(long native_object, char[] text,
- int contextStart, int contextLength, int flags, int offset, int cursorOpt);
+ int contextStart, int contextLength, int dir, int offset, int cursorOpt);
private native int native_getTextRunCursor(long native_object, String text,
- int contextStart, int contextEnd, int flags, int offset, int cursorOpt);
+ int contextStart, int contextEnd, int dir, int offset, int cursorOpt);
private static native void native_getTextPath(long native_object, long native_typeface,
int bidiFlags, char[] text, int index, int count, float x, float y, long path);
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index c600f47..c40a66d 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -62,7 +62,7 @@
}
mNativePath = init2(valNative);
}
-
+
/**
* Clear any lines and curves from the path, making it empty.
* This does NOT change the fill-type setting.
@@ -205,7 +205,7 @@
* Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside.
*/
INVERSE_EVEN_ODD(3);
-
+
FillType(int ni) {
nativeInt = ni;
}
@@ -425,7 +425,7 @@
* the path is different from the path's current last point, then an
* automatic lineTo() is added to connect the current contour to the
* start of the arc. However, if the path is empty, then we call moveTo()
- * with the first point of the arc. The sweep angle is tread mod 360.
+ * with the first point of the arc.
*
* @param oval The bounds of oval defining shape and size of the arc
* @param startAngle Starting angle (in degrees) where the arc begins
@@ -435,10 +435,9 @@
*/
public void arcTo(RectF oval, float startAngle, float sweepAngle,
boolean forceMoveTo) {
- isSimplePath = false;
- native_arcTo(mNativePath, oval, startAngle, sweepAngle, forceMoveTo);
+ arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, forceMoveTo);
}
-
+
/**
* Append the specified arc to the path as a new contour. If the start of
* the path is different from the path's current last point, then an
@@ -451,10 +450,27 @@
* @param sweepAngle Sweep angle (in degrees) measured clockwise
*/
public void arcTo(RectF oval, float startAngle, float sweepAngle) {
- isSimplePath = false;
- native_arcTo(mNativePath, oval, startAngle, sweepAngle, false);
+ arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, false);
}
-
+
+ /**
+ * Append the specified arc to the path as a new contour. If the start of
+ * the path is different from the path's current last point, then an
+ * automatic lineTo() is added to connect the current contour to the
+ * start of the arc. However, if the path is empty, then we call moveTo()
+ * with the first point of the arc.
+ *
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise, treated
+ * mod 360.
+ * @param forceMoveTo If true, always begin a new contour with the arc
+ */
+ public void arcTo(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, boolean forceMoveTo) {
+ isSimplePath = false;
+ native_arcTo(mNativePath, left, top, right, bottom, startAngle, sweepAngle, forceMoveTo);
+ }
+
/**
* Close the current contour. If the current point is not equal to the
* first point of the contour, a line segment is automatically added.
@@ -473,13 +489,13 @@
CW (1), // must match enum in SkPath.h
/** counter-clockwise */
CCW (2); // must match enum in SkPath.h
-
+
Direction(int ni) {
nativeInt = ni;
}
final int nativeInt;
}
-
+
private void detectSimplePath(float left, float top, float right, float bottom, Direction dir) {
if (mLastDirection == null) {
mLastDirection = dir;
@@ -557,11 +573,19 @@
* @param sweepAngle Sweep angle (in degrees) measured clockwise
*/
public void addArc(RectF oval, float startAngle, float sweepAngle) {
- if (oval == null) {
- throw new NullPointerException("need oval parameter");
- }
+ addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle);
+ }
+
+ /**
+ * Add the specified arc to the path as a new contour.
+ *
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise
+ */
+ public void addArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle) {
isSimplePath = false;
- native_addArc(mNativePath, oval, startAngle, sweepAngle);
+ native_addArc(mNativePath, left, top, right, bottom, startAngle, sweepAngle);
}
/**
@@ -573,13 +597,22 @@
* @param dir The direction to wind the round-rectangle's contour
*/
public void addRoundRect(RectF rect, float rx, float ry, Direction dir) {
- if (rect == null) {
- throw new NullPointerException("need rect parameter");
- }
- isSimplePath = false;
- native_addRoundRect(mNativePath, rect, rx, ry, dir.nativeInt);
+ addRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, dir);
}
-
+
+ /**
+ * Add a closed round-rectangle contour to the path
+ *
+ * @param rx The x-radius of the rounded corners on the round-rectangle
+ * @param ry The y-radius of the rounded corners on the round-rectangle
+ * @param dir The direction to wind the round-rectangle's contour
+ */
+ public void addRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+ Direction dir) {
+ isSimplePath = false;
+ native_addRoundRect(mNativePath, left, top, right, bottom, rx, ry, dir.nativeInt);
+ }
+
/**
* Add a closed round-rectangle contour to the path. Each corner receives
* two radius values [X, Y]. The corners are ordered top-left, top-right,
@@ -593,13 +626,26 @@
if (rect == null) {
throw new NullPointerException("need rect parameter");
}
+ addRoundRect(rect.left, rect.top, rect.right, rect.bottom, radii, dir);
+ }
+
+ /**
+ * Add a closed round-rectangle contour to the path. Each corner receives
+ * two radius values [X, Y]. The corners are ordered top-left, top-right,
+ * bottom-right, bottom-left
+ *
+ * @param radii Array of 8 values, 4 pairs of [X,Y] radii
+ * @param dir The direction to wind the round-rectangle's contour
+ */
+ public void addRoundRect(float left, float top, float right, float bottom, float[] radii,
+ Direction dir) {
if (radii.length < 8) {
throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
}
isSimplePath = false;
- native_addRoundRect(mNativePath, rect, radii, dir.nativeInt);
+ native_addRoundRect(mNativePath, left, top, right, bottom, radii, dir.nativeInt);
}
-
+
/**
* Add a copy of src to the path, offset by (dx,dy)
*
@@ -755,19 +801,24 @@
float x2, float y2, float x3, float y3);
private static native void native_rCubicTo(long nPath, float x1, float y1,
float x2, float y2, float x3, float y3);
- private static native void native_arcTo(long nPath, RectF oval,
- float startAngle, float sweepAngle, boolean forceMoveTo);
+ private static native void native_arcTo(long nPath, float left, float top,
+ float right, float bottom, float startAngle,
+ float sweepAngle, boolean forceMoveTo);
private static native void native_close(long nPath);
private static native void native_addRect(long nPath, float left, float top,
float right, float bottom, int dir);
private static native void native_addOval(long nPath, float left, float top,
float right, float bottom, int dir);
private static native void native_addCircle(long nPath, float x, float y, float radius, int dir);
- private static native void native_addArc(long nPath, RectF oval,
- float startAngle, float sweepAngle);
- private static native void native_addRoundRect(long nPath, RectF rect,
+ private static native void native_addArc(long nPath, float left, float top,
+ float right, float bottom,
+ float startAngle, float sweepAngle);
+ private static native void native_addRoundRect(long nPath, float left, float top,
+ float right, float bottom,
float rx, float ry, int dir);
- private static native void native_addRoundRect(long nPath, RectF r, float[] radii, int dir);
+ private static native void native_addRoundRect(long nPath, float left, float top,
+ float right, float bottom,
+ float[] radii, int dir);
private static native void native_addPath(long nPath, long src, float dx, float dy);
private static native void native_addPath(long nPath, long src);
private static native void native_addPath(long nPath, long src, long matrix);
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index de458af..a021165 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -53,7 +53,7 @@
public Picture(Picture src) {
this(nativeConstructor(src != null ? src.mNativePicture : 0), false);
}
-
+
/**
* To record a picture, call beginRecording() and then draw into the Canvas
* that is returned. Nothing we appear on screen, but all of the draw
@@ -67,7 +67,7 @@
mRecordingCanvas = new RecordingCanvas(this, ni);
return mRecordingCanvas;
}
-
+
/**
* Call endRecording when the picture is built. After this call, the picture
* may be drawn, but the canvas that was returned by beginRecording must not
@@ -92,16 +92,19 @@
* does not reflect (per se) the content of the picture.
*/
public native int getHeight();
-
+
/**
- * Draw this picture on the canvas. The picture may have the side effect
- * of changing the matrix and clip of the canvas.
- *
+ * Draw this picture on the canvas.
+ * <p>
+ * Prior to {@link android.os.Build.VERSION_CODES#L}, this call could
+ * have the side effect of changing the matrix and clip of the canvas
+ * if this picture had imbalanced saves/restores.
+ *
* <p>
* <strong>Note:</strong> This forces the picture to internally call
* {@link Picture#endRecording()} in order to prepare for playback.
*
- * @param canvas The picture is drawn to this canvas
+ * @param canvas The picture is drawn to this canvas
*/
public void draw(Canvas canvas) {
if (mRecordingCanvas != null) {
@@ -119,7 +122,7 @@
* <p>
* <strong>Note:</strong> a picture created from an input stream cannot be
* replayed on a hardware accelerated canvas.
- *
+ *
* @see #writeToStream(java.io.OutputStream)
* @deprecated The recommended alternative is to not use writeToStream and
* instead draw the picture into a Bitmap from which you can persist it as
@@ -167,7 +170,7 @@
final long ni() {
return mNativePicture;
}
-
+
private Picture(long nativePicture, boolean fromStream) {
if (nativePicture == 0) {
throw new RuntimeException();
@@ -187,7 +190,7 @@
private static native boolean nativeWriteToStream(long nativePicture,
OutputStream stream, byte[] storage);
private static native void nativeDestructor(long nativePicture);
-
+
private static class RecordingCanvas extends Canvas {
private final Picture mPicture;
@@ -195,7 +198,7 @@
super(nativeCanvas);
mPicture = pict;
}
-
+
@Override
public void setBitmap(Bitmap bitmap) {
throw new RuntimeException(
diff --git a/graphics/java/android/graphics/drawable/Animatable.java b/graphics/java/android/graphics/drawable/Animatable.java
index 9dc62c3..4edfad4 100644
--- a/graphics/java/android/graphics/drawable/Animatable.java
+++ b/graphics/java/android/graphics/drawable/Animatable.java
@@ -32,7 +32,7 @@
/**
* Indicates whether the animation is running.
- *
+ *
* @return True if the animation is running, false otherwise.
*/
boolean isRunning();
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index e8024f7..0fd4423 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -19,6 +19,8 @@
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.ColorFilter;
+import android.graphics.PorterDuff.Mode;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
@@ -88,6 +90,7 @@
canvas.restoreToCount(saveCount);
}
+ @Override
public void start() {
if (!mRunning) {
mRunning = true;
@@ -95,11 +98,13 @@
}
}
+ @Override
public void stop() {
mRunning = false;
unscheduleSelf(this);
}
+ @Override
public boolean isRunning() {
return mRunning;
}
@@ -108,10 +113,11 @@
unscheduleSelf(this);
scheduleSelf(this, SystemClock.uptimeMillis() + mState.mFrameDuration);
}
-
+
+ @Override
public void run() {
// TODO: This should be computed in draw(Canvas), based on the amount
- // of time since the last frame drawn
+ // of time since the last frame drawn
mCurrentDegrees += mIncrement;
if (mCurrentDegrees > (360.0f - mIncrement)) {
mCurrentDegrees = 0.0f;
@@ -119,7 +125,7 @@
invalidateSelf();
nextFrame();
}
-
+
@Override
public boolean setVisible(boolean visible, boolean restart) {
mState.mDrawable.setVisible(visible, restart);
@@ -133,8 +139,8 @@
unscheduleSelf(this);
}
return changed;
- }
-
+ }
+
/**
* Returns the drawable rotated by this RotateDrawable.
*/
@@ -148,7 +154,7 @@
| mState.mChangingConfigurations
| mState.mDrawable.getChangingConfigurations();
}
-
+
@Override
public void setAlpha(int alpha) {
mState.mDrawable.setAlpha(alpha);
@@ -165,10 +171,16 @@
}
@Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ mState.mDrawable.setTint(tint, tintMode);
+ }
+
+ @Override
public int getOpacity() {
return mState.mDrawable.getOpacity();
}
+ @Override
public void invalidateDrawable(Drawable who) {
final Callback callback = getCallback();
if (callback != null) {
@@ -176,6 +188,7 @@
}
}
+ @Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
final Callback callback = getCallback();
if (callback != null) {
@@ -183,6 +196,7 @@
}
}
+ @Override
public void unscheduleDrawable(Drawable who, Runnable what) {
final Callback callback = getCallback();
if (callback != null) {
@@ -194,7 +208,7 @@
public boolean getPadding(Rect padding) {
return mState.mDrawable.getPadding(padding);
}
-
+
@Override
public boolean isStateful() {
return mState.mDrawable.isStateful();
@@ -206,6 +220,16 @@
}
@Override
+ protected boolean onLevelChange(int level) {
+ return mState.mDrawable.setLevel(level);
+ }
+
+ @Override
+ protected boolean onStateChange(int[] state) {
+ return mState.mDrawable.setState(state);
+ }
+
+ @Override
public int getIntrinsicWidth() {
return mState.mDrawable.getIntrinsicWidth();
}
@@ -231,11 +255,11 @@
final TypedArray a = r.obtainAttributes(attrs, R.styleable.AnimatedRotateDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible);
-
+
TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX);
final boolean pivotXRel = tv.type == TypedValue.TYPE_FRACTION;
final float pivotX = pivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
-
+
tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY);
final boolean pivotYRel = tv.type == TypedValue.TYPE_FRACTION;
final float pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
@@ -250,7 +274,7 @@
}
a.recycle();
-
+
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
@@ -306,7 +330,7 @@
Drawable mDrawable;
int mChangingConfigurations;
-
+
boolean mPivotXRel;
float mPivotX;
boolean mPivotYRel;
@@ -315,7 +339,7 @@
int mFramesCount;
private boolean mCanConstantState;
- private boolean mCheckedConstantState;
+ private boolean mCheckedConstantState;
public AnimatedRotateState(AnimatedRotateState source, AnimatedRotateDrawable owner,
Resources res) {
@@ -341,12 +365,12 @@
public Drawable newDrawable() {
return new AnimatedRotateDrawable(this, null);
}
-
+
@Override
public Drawable newDrawable(Resources res) {
return new AnimatedRotateDrawable(this, res);
}
-
+
@Override
public int getChangingConfigurations() {
return mChangingConfigurations;
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index a5a074c..e1dec9d 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -537,4 +537,3 @@
}
}
}
-
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
new file mode 100644
index 0000000..968c0ec
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -0,0 +1,250 @@
+/*
+ * 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.graphics.drawable;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * AnimatedVectorDrawable can use ObjectAnimator and AnimatorSet to animate
+ * the property of the VectorDrawable.
+ *
+ * @hide
+ */
+public class AnimatedVectorDrawable extends Drawable implements Animatable {
+ private static final String LOGTAG = AnimatedVectorDrawable.class.getSimpleName();
+
+ private static final String ANIMATED_VECTOR = "animated-vector";
+ private static final String TARGET = "target";
+
+ private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
+
+ private final AnimatedVectorDrawableState mAnimatedVectorState;
+
+
+ public AnimatedVectorDrawable() {
+ mAnimatedVectorState = new AnimatedVectorDrawableState(
+ new AnimatedVectorDrawableState(null));
+ }
+
+ private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res,
+ Theme theme) {
+ // TODO: Correctly handle the constant state for AVD.
+ mAnimatedVectorState = new AnimatedVectorDrawableState(state);
+ if (theme != null && canApplyTheme()) {
+ applyTheme(theme);
+ }
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ return null;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ mAnimatedVectorState.mVectorDrawable.draw(canvas);
+ if (isRunning()) {
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ mAnimatedVectorState.mVectorDrawable.setBounds(bounds);
+ }
+
+ @Override
+ public int getAlpha() {
+ return mAnimatedVectorState.mVectorDrawable.getAlpha();
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mAnimatedVectorState.mVectorDrawable.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ mAnimatedVectorState.mVectorDrawable.setColorFilter(colorFilter);
+ }
+
+ @Override
+ public int getOpacity() {
+ return mAnimatedVectorState.mVectorDrawable.getOpacity();
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mAnimatedVectorState.mVectorDrawable.getIntrinsicWidth();
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mAnimatedVectorState.mVectorDrawable.getIntrinsicHeight();
+ }
+
+ @Override
+ public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
+ throws XmlPullParserException, IOException {
+
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG) {
+ final String tagName = parser.getName();
+ if (ANIMATED_VECTOR.equals(tagName)) {
+ final TypedArray a = obtainAttributes(res, theme, attrs,
+ R.styleable.AnimatedVectorDrawable);
+ int drawableRes = a.getResourceId(
+ R.styleable.AnimatedVectorDrawable_drawable, 0);
+ if (drawableRes != 0) {
+ mAnimatedVectorState.mVectorDrawable = (VectorDrawable) res.getDrawable(
+ drawableRes);
+ }
+ a.recycle();
+ } else if (TARGET.equals(tagName)) {
+ final TypedArray a = obtainAttributes(res, theme, attrs,
+ R.styleable.AnimatedVectorDrawableTarget);
+ final String target = a.getString(
+ R.styleable.AnimatedVectorDrawableTarget_name);
+
+ int id = a.getResourceId(
+ R.styleable.AnimatedVectorDrawableTarget_animation, 0);
+ if (id != 0) {
+ Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id);
+ setupAnimatorsForTarget(target, objectAnimator);
+ }
+ a.recycle();
+ }
+ }
+
+ eventType = parser.next();
+ }
+ }
+
+ @Override
+ public boolean canApplyTheme() {
+ return super.canApplyTheme() || mAnimatedVectorState != null
+ && mAnimatedVectorState.canApplyTheme();
+ }
+
+ @Override
+ public void applyTheme(Theme t) {
+ super.applyTheme(t);
+
+ final VectorDrawable vectorDrawable = mAnimatedVectorState.mVectorDrawable;
+ if (vectorDrawable != null && vectorDrawable.canApplyTheme()) {
+ vectorDrawable.applyTheme(t);
+ }
+ }
+
+ private static class AnimatedVectorDrawableState extends ConstantState {
+ int mChangingConfigurations;
+ VectorDrawable mVectorDrawable;
+ ArrayList<Animator> mAnimators;
+
+ public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy) {
+ if (copy != null) {
+ mChangingConfigurations = copy.mChangingConfigurations;
+ // TODO: Make sure the constant state are handled correctly.
+ mVectorDrawable = new VectorDrawable();
+ mAnimators = new ArrayList<Animator>();
+ }
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new AnimatedVectorDrawable(this, null, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new AnimatedVectorDrawable(this, res, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res, Theme theme) {
+ return new AnimatedVectorDrawable(this, res, theme);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+ }
+
+ private void setupAnimatorsForTarget(String name, Animator animator) {
+ Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name);
+ animator.setTarget(target);
+ mAnimatedVectorState.mAnimators.add(animator);
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.v(LOGTAG, "add animator for target " + name + " " + animator);
+ }
+ }
+
+ @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;
+ }
+
+ @Override
+ public void start() {
+ 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.isPaused()) {
+ animator.resume();
+ } else if (!animator.isRunning()) {
+ animator.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.pause();
+ }
+ }
+}
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 16548d0..0740761 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -28,7 +28,6 @@
import android.util.AttributeSet;
/**
- *
* An object used to create frame-by-frame animations, defined by a series of Drawable objects,
* which can be used as a View object's background.
* <p>
@@ -91,10 +90,10 @@
@Override
public boolean setVisible(boolean visible, boolean restart) {
- boolean changed = super.setVisible(visible, restart);
+ final boolean changed = super.setVisible(visible, restart);
if (visible) {
if (changed || restart) {
- setFrame(0, true, restart || mCurFrame >= 0);
+ setFrame(0, true, mAnimating);
}
} else {
unscheduleSelf(this);
@@ -114,6 +113,7 @@
* @see #isRunning()
* @see #stop()
*/
+ @Override
public void start() {
if (!isRunning()) {
run();
@@ -127,6 +127,7 @@
* @see #isRunning()
* @see #start()
*/
+ @Override
public void stop() {
if (isRunning()) {
unscheduleSelf(this);
@@ -138,6 +139,7 @@
*
* @return true if the animation is running, false otherwise
*/
+ @Override
public boolean isRunning() {
return mAnimating;
}
@@ -148,6 +150,7 @@
*
* @see #start()
*/
+ @Override
public void run() {
nextFrame(false);
}
@@ -165,41 +168,41 @@
public int getNumberOfFrames() {
return mAnimationState.getChildCount();
}
-
+
/**
* @return The Drawable at the specified frame index
*/
public Drawable getFrame(int index) {
return mAnimationState.getChild(index);
}
-
+
/**
- * @return The duration in milliseconds of the frame at the
+ * @return The duration in milliseconds of the frame at the
* specified index
*/
public int getDuration(int i) {
return mAnimationState.mDurations[i];
}
-
+
/**
* @return True of the animation will play once, false otherwise
*/
public boolean isOneShot() {
return mAnimationState.mOneShot;
}
-
+
/**
* Sets whether the animation should play once or repeat.
- *
+ *
* @param oneShot Pass true if the animation should only play once
*/
public void setOneShot(boolean oneShot) {
mAnimationState.mOneShot = oneShot;
}
-
+
/**
* Add a frame to the animation
- *
+ *
* @param frame The frame to add
* @param duration How long in milliseconds the frame should appear
*/
@@ -209,7 +212,7 @@
setFrame(0, true, false);
}
}
-
+
private void nextFrame(boolean unschedule) {
int next = mCurFrame+1;
final int N = mAnimationState.getChildCount();
@@ -239,21 +242,21 @@
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
-
+
TypedArray a = r.obtainAttributes(attrs,
com.android.internal.R.styleable.AnimationDrawable);
super.inflateWithAttributes(r, parser, a,
com.android.internal.R.styleable.AnimationDrawable_visible);
-
+
mAnimationState.setVariablePadding(a.getBoolean(
com.android.internal.R.styleable.AnimationDrawable_variablePadding, false));
-
+
mAnimationState.mOneShot = a.getBoolean(
com.android.internal.R.styleable.AnimationDrawable_oneshot, false);
-
+
a.recycle();
-
+
int type;
final int innerDepth = parser.getDepth()+1;
@@ -267,7 +270,7 @@
if (depth > innerDepth || !parser.getName().equals("item")) {
continue;
}
-
+
a = r.obtainAttributes(attrs, com.android.internal.R.styleable.AnimationDrawableItem);
int duration = a.getInt(
com.android.internal.R.styleable.AnimationDrawableItem_duration, -1);
@@ -278,9 +281,9 @@
}
int drawableRes = a.getResourceId(
com.android.internal.R.styleable.AnimationDrawableItem_drawable, 0);
-
+
a.recycle();
-
+
Drawable dr;
if (drawableRes != 0) {
dr = r.getDrawable(drawableRes);
@@ -295,7 +298,7 @@
}
dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
}
-
+
mAnimationState.addFrame(dr, duration);
if (dr != null) {
dr.setCallback(this);
@@ -342,7 +345,7 @@
}
public void addFrame(Drawable dr, int dur) {
- // Do not combine the following. The array index must be evaluated before
+ // Do not combine the following. The array index must be evaluated before
// the array is accessed because super.addChild(dr) has a side effect on mDurations.
int pos = super.addChild(dr);
mDurations[pos] = dur;
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index c95ac82..be940df 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -31,6 +31,7 @@
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.ColorDrawable.ColorState;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.Shader;
@@ -618,9 +619,11 @@
@Override
public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) {
- mBitmapState.mTint = tint;
- mBitmapState.mTintMode = tintMode;
- computeTintFilter();
+ final BitmapState state = mBitmapState;
+ state.mTint = tint;
+ state.mTintMode = tintMode;
+
+ mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
invalidateSelf();
}
@@ -638,21 +641,6 @@
return mBitmapState.mTintMode;
}
- private void computeTintFilter() {
- final BitmapState state = mBitmapState;
- if (state.mTint != null && state.mTintMode != null) {
- final int color = state.mTint.getColorForState(getState(), 0);
- if (mTintFilter != null) {
- mTintFilter.setColor(color);
- mTintFilter.setMode(state.mTintMode);
- } else {
- mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
- }
- } else {
- mTintFilter = null;
- }
- }
-
/**
* @hide Candidate for future API inclusion
*/
@@ -679,17 +667,11 @@
@Override
protected boolean onStateChange(int[] stateSet) {
- final ColorStateList tint = mBitmapState.mTint;
- if (tint != null) {
- final int newColor = tint.getColorForState(stateSet, 0);
- final int oldColor = mTintFilter.getColor();
- if (oldColor != newColor) {
- mTintFilter.setColor(newColor);
- invalidateSelf();
- return true;
- }
+ final BitmapState state = mBitmapState;
+ if (state.mTint != null && state.mTintMode != null) {
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ return true;
}
-
return false;
}
@@ -706,10 +688,24 @@
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.BitmapDrawable);
updateStateFromTypedArray(a);
+ verifyState(a);
a.recycle();
}
/**
+ * Ensures all required attributes are set.
+ *
+ * @throws XmlPullParserException if any required attributes are missing
+ */
+ private void verifyState(TypedArray a) throws XmlPullParserException {
+ final BitmapState state = mBitmapState;
+ if (state.mBitmap == null) {
+ throw new XmlPullParserException(a.getPositionDescription() +
+ ": <bitmap> requires a valid src attribute");
+ }
+ }
+
+ /**
* Updates the constant state from the values in the typed array.
*/
private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
@@ -912,6 +908,7 @@
*/
private BitmapDrawable(BitmapState state, Resources res, Theme theme) {
if (theme != null && state.canApplyTheme()) {
+ // If we need to apply a theme, implicitly mutate.
mBitmapState = new BitmapState(state);
applyTheme(theme);
} else {
@@ -931,7 +928,7 @@
mTargetDensity = state.mTargetDensity;
}
- computeTintFilter();
+ updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
computeBitmapSize();
}
}
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 3ac9972..174de3a 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -19,10 +19,12 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
import android.graphics.*;
+import android.graphics.PorterDuff.Mode;
import android.view.Gravity;
import android.util.AttributeSet;
@@ -52,7 +54,7 @@
public static final int HORIZONTAL = 1;
public static final int VERTICAL = 2;
-
+
ClipDrawable() {
this(null, null);
}
@@ -111,6 +113,7 @@
// overrides from Drawable.Callback
+ @Override
public void invalidateDrawable(Drawable who) {
final Callback callback = getCallback();
if (callback != null) {
@@ -118,6 +121,7 @@
}
}
+ @Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
final Callback callback = getCallback();
if (callback != null) {
@@ -125,6 +129,7 @@
}
}
+ @Override
public void unscheduleDrawable(Drawable who, Runnable what) {
final Callback callback = getCallback();
if (callback != null) {
@@ -169,6 +174,11 @@
}
@Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ mClipState.mDrawable.setTint(tint, tintMode);
+ }
+
+ @Override
public int getOpacity() {
return mClipState.mDrawable.getOpacity();
}
@@ -197,7 +207,7 @@
@Override
public void draw(Canvas canvas) {
-
+
if (mClipState.mDrawable.getLevel() == 0) {
return;
}
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index df5ca33..3716182 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -17,6 +17,8 @@
package android.graphics.drawable;
import android.graphics.*;
+import android.graphics.PorterDuff.Mode;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
@@ -39,9 +41,13 @@
* @attr ref android.R.styleable#ColorDrawable_color
*/
public class ColorDrawable extends Drawable {
+ private final Paint mPaint = new Paint();
+
@ViewDebug.ExportedProperty(deepExport = true, prefix = "state_")
private ColorState mColorState;
- private final Paint mPaint = new Paint();
+ private ColorStateList mTint;
+ private PorterDuffColorFilter mTintFilter;
+
private boolean mMutated;
/**
@@ -84,9 +90,17 @@
@Override
public void draw(Canvas canvas) {
- if ((mColorState.mUseColor >>> 24) != 0) {
+ final ColorFilter colorFilter = mPaint.getColorFilter();
+ if ((mColorState.mUseColor >>> 24) != 0 || colorFilter != null || mTintFilter != null) {
+ if (colorFilter == null) {
+ mPaint.setColorFilter(mTintFilter);
+ }
+
mPaint.setColor(mColorState.mUseColor);
canvas.drawRect(getBounds(), mPaint);
+
+ // Restore original color filter.
+ mPaint.setColorFilter(colorFilter);
}
}
@@ -141,16 +155,51 @@
}
/**
- * Setting a color filter on a ColorDrawable has no effect.
+ * Sets the color filter applied to this color.
+ * <p>
+ * Only supported on version {@link android.os.Build.VERSION_CODES#L} and
+ * above. Calling this method has no effect on earlier versions.
*
- * @param colorFilter Ignore.
+ * @see android.graphics.drawable.Drawable#setColorFilter(ColorFilter)
*/
@Override
public void setColorFilter(ColorFilter colorFilter) {
+ mPaint.setColorFilter(colorFilter);
+ }
+
+ @Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ final ColorState state = mColorState;
+ if (state.mTint != tint || state.mTintMode != tintMode) {
+ state.mTint = tint;
+ state.mTintMode = tintMode;
+
+ mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ protected boolean onStateChange(int[] stateSet) {
+ final ColorState state = mColorState;
+ if (state.mTint != null && state.mTintMode != null) {
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isStateful() {
+ return mTint != null && mTint.isStateful();
}
@Override
public int getOpacity() {
+ if (mTintFilter != null || mPaint.getColorFilter() != null) {
+ return PixelFormat.TRANSLUCENT;
+ }
+
switch (mColorState.mUseColor >>> 24) {
case 255:
return PixelFormat.OPAQUE;
@@ -165,8 +214,7 @@
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs, theme);
- final TypedArray a = obtainAttributes(
- r, theme, attrs, R.styleable.ColorDrawable);
+ final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ColorDrawable);
inflateStateFromTypedArray(a);
a.recycle();
}
@@ -225,21 +273,25 @@
}
final static class ColorState extends ConstantState {
+ int[] mThemeAttrs;
int mBaseColor; // base color, independent of setAlpha()
@ViewDebug.ExportedProperty
int mUseColor; // basecolor modulated by setAlpha()
int mChangingConfigurations;
- int[] mThemeAttrs;
+ ColorStateList mTint;
+ Mode mTintMode;
ColorState() {
// Empty constructor.
}
ColorState(ColorState state) {
+ mThemeAttrs = state.mThemeAttrs;
mBaseColor = state.mBaseColor;
mUseColor = state.mUseColor;
mChangingConfigurations = state.mChangingConfigurations;
- mThemeAttrs = state.mThemeAttrs;
+ mTint = state.mTint;
+ mTintMode = state.mTintMode;
}
@Override
@@ -276,6 +328,6 @@
mColorState = state;
}
- // No local properties to initialize.
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
}
}
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 3a32e80..40b55a7 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -17,13 +17,6 @@
package android.graphics.drawable;
import android.annotation.NonNull;
-import android.graphics.Insets;
-import android.graphics.Xfermode;
-import android.os.Trace;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
@@ -31,15 +24,19 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.ColorFilter;
+import android.graphics.Insets;
import android.graphics.NinePatch;
import android.graphics.Outline;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
+import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.Region;
-import android.graphics.PorterDuff.Mode;
+import android.graphics.Xfermode;
+import android.os.Trace;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.StateSet;
@@ -47,6 +44,9 @@
import android.util.Xml;
import android.view.View;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
@@ -209,7 +209,7 @@
* stored bounds of this drawable.
*
* @see #copyBounds()
- * @see #copyBounds(android.graphics.Rect)
+ * @see #copyBounds(android.graphics.Rect)
*/
public final Rect getBounds() {
if (mBounds == ZERO_BOUNDS_RECT) {
@@ -328,8 +328,8 @@
* that want to support animated drawables.
*
* @param cb The client's Callback implementation.
- *
- * @see #getCallback()
+ *
+ * @see #getCallback()
*/
public final void setCallback(Callback cb) {
mCallback = new WeakReference<Callback>(cb);
@@ -338,10 +338,10 @@
/**
* Return the current {@link Callback} implementation attached to this
* Drawable.
- *
+ *
* @return A {@link Callback} instance or null if no callback was set.
- *
- * @see #setCallback(android.graphics.drawable.Drawable.Callback)
+ *
+ * @see #setCallback(android.graphics.drawable.Drawable.Callback)
*/
public Callback getCallback() {
if (mCallback != null) {
@@ -349,15 +349,15 @@
}
return null;
}
-
+
/**
* Use the current {@link Callback} implementation to have this Drawable
* redrawn. Does nothing if there is no Callback attached to the
* Drawable.
*
* @see Callback#invalidateDrawable
- * @see #getCallback()
- * @see #setCallback(android.graphics.drawable.Drawable.Callback)
+ * @see #getCallback()
+ * @see #setCallback(android.graphics.drawable.Drawable.Callback)
*/
public void invalidateSelf() {
final Callback callback = getCallback();
@@ -931,7 +931,7 @@
Rects only to drop them on the floor.
*/
Rect pad = new Rect();
-
+
// Special stuff for compatibility mode: if the target density is not
// the same as the display density, but the resource -is- the same as
// the display density, then don't scale it down to the target density.
@@ -1023,9 +1023,9 @@
drawable = new StateListDrawable();
} else if (name.equals("animated-selector")) {
drawable = new AnimatedStateListDrawable();
- } else if (name.equals("quantum-progress")) {
+ } else if (name.equals("material-progress")) {
// TODO: Replace this with something less ridiculous.
- drawable = new QuantumProgressDrawable();
+ drawable = new MaterialProgressDrawable();
} else if (name.equals("level-list")) {
drawable = new LevelListDrawable();
} else if (name.equals("layer-list")) {
@@ -1040,6 +1040,8 @@
drawable = new GradientDrawable();
} else if (name.equals("vector")) {
drawable = new VectorDrawable();
+ } else if (name.equals("animated-vector")) {
+ drawable = new AnimatedVectorDrawable();
} else if (name.equals("scale")) {
drawable = new ScaleDrawable();
} else if (name.equals("clip")) {
@@ -1047,7 +1049,7 @@
} else if (name.equals("rotate")) {
drawable = new RotateDrawable();
} else if (name.equals("animated-rotate")) {
- drawable = new AnimatedRotateDrawable();
+ drawable = new AnimatedRotateDrawable();
} else if (name.equals("animation-list")) {
drawable = new AnimationDrawable();
} else if (name.equals("inset")) {
@@ -1224,6 +1226,26 @@
}
/**
+ * Ensures the tint filter is consistent with the current tint color and
+ * mode.
+ */
+ PorterDuffColorFilter updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint,
+ PorterDuff.Mode tintMode) {
+ if (tint == null || tintMode == null) {
+ return null;
+ }
+
+ final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
+ if (tintFilter == null) {
+ return new PorterDuffColorFilter(color, tintMode);
+ }
+
+ tintFilter.setColor(color);
+ tintFilter.setMode(tintMode);
+ return tintFilter;
+ }
+
+ /**
* Obtains styled attributes from the theme, if available, or unstyled
* resources if the theme is null.
*/
@@ -1238,8 +1260,10 @@
/**
* Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode
* attribute's enum value.
+ *
+ * @hide
*/
- static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
+ public static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
switch (value) {
case 3: return Mode.SRC_OVER;
case 5: return Mode.SRC_IN;
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 2aef39f..8be6eb7 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -16,6 +16,7 @@
package android.graphics.drawable;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.graphics.Canvas;
@@ -23,6 +24,7 @@
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.PorterDuff.Mode;
import android.os.SystemClock;
import android.util.LayoutDirection;
import android.util.SparseArray;
@@ -151,7 +153,7 @@
@Override
public void setColorFilter(ColorFilter cf) {
- mDrawableContainerState.mHasColorFilter = true;
+ mDrawableContainerState.mHasColorFilter = (cf != null);
if (mDrawableContainerState.mColorFilter != cf) {
mDrawableContainerState.mColorFilter = cf;
@@ -162,6 +164,20 @@
}
}
+ @Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ mDrawableContainerState.mHasTint = (tint != null && tintMode != null);
+
+ if (mDrawableContainerState.mTint != tint || mDrawableContainerState.mTintMode != tintMode) {
+ mDrawableContainerState.mTint = tint;
+ mDrawableContainerState.mTintMode = tintMode;
+
+ if (mCurrDrawable != null) {
+ mCurrDrawable.mutate().setTint(tint, tintMode);
+ }
+ }
+ }
+
/**
* Change the global fade duration when a new drawable is entering
* the scene.
@@ -396,6 +412,8 @@
}
if (mDrawableContainerState.mHasColorFilter) {
d.setColorFilter(mDrawableContainerState.mColorFilter);
+ } else if (mDrawableContainerState.mHasTint) {
+ d.setTint(mDrawableContainerState.mTint, mDrawableContainerState.mTintMode);
}
d.setVisible(isVisible(), true);
d.setDither(mDrawableContainerState.mDither);
@@ -566,6 +584,10 @@
ColorFilter mColorFilter;
boolean mHasColorFilter;
+ ColorStateList mTint;
+ Mode mTintMode;
+ boolean mHasTint;
+
DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
Resources res) {
mOwner = owner;
@@ -588,6 +610,9 @@
mAutoMirrored = orig.mAutoMirrored;
mColorFilter = orig.mColorFilter;
mHasColorFilter = orig.mHasColorFilter;
+ mTint = orig.mTint;
+ mTintMode = orig.mTintMode;
+ mHasTint = orig.mHasTint;
// Cloning the following values may require creating futures.
mConstantPadding = orig.getConstantPadding();
@@ -741,7 +766,7 @@
final int N = mNumChildren;
final Drawable[] drawables = mDrawables;
for (int i = 0; i < N; i++) {
- final Drawable d = drawables[i];
+ final Drawable d = drawables[i];
if (d != null) {
if (d.canApplyTheme()) {
return true;
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 241b89e..005b8ef 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -1662,9 +1662,12 @@
* @param theme Theme to apply to the drawable
*/
private GradientDrawable(GradientState state, Theme theme) {
- mGradientState = new GradientState(state);
if (theme != null && state.canApplyTheme()) {
+ // If we need to apply a theme, implicitly mutate.
+ mGradientState = new GradientState(state);
applyTheme(theme);
+ } else {
+ mGradientState = state;
}
initializeWithState(state);
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 9e0ab86..220e81c 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -19,10 +19,12 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
import android.graphics.*;
+import android.graphics.PorterDuff.Mode;
import android.util.AttributeSet;
import android.util.Log;
@@ -44,8 +46,7 @@
* @attr ref android.R.styleable#InsetDrawable_insetTop
* @attr ref android.R.styleable#InsetDrawable_insetBottom
*/
-public class InsetDrawable extends Drawable implements Drawable.Callback
-{
+public class InsetDrawable extends Drawable implements Drawable.Callback {
// Most of this is copied from ScaleDrawable.
private InsetState mInsetState;
private final Rect mTmpRect = new Rect();
@@ -62,13 +63,13 @@
public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,
int insetRight, int insetBottom) {
this(null, null);
-
+
mInsetState.mDrawable = drawable;
mInsetState.mInsetLeft = insetLeft;
mInsetState.mInsetTop = insetTop;
mInsetState.mInsetRight = insetRight;
mInsetState.mInsetBottom = insetBottom;
-
+
if (drawable != null) {
drawable.setCallback(this);
}
@@ -78,7 +79,7 @@
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
int type;
-
+
TypedArray a = r.obtainAttributes(attrs,
com.android.internal.R.styleable.InsetDrawable);
@@ -168,7 +169,7 @@
| mInsetState.mChangingConfigurations
| mInsetState.mDrawable.getChangingConfigurations();
}
-
+
@Override
public boolean getPadding(Rect padding) {
boolean pad = mInsetState.mDrawable.getPadding(padding);
@@ -178,7 +179,7 @@
padding.top += mInsetState.mInsetTop;
padding.bottom += mInsetState.mInsetBottom;
- if (pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight |
+ if (pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight |
mInsetState.mInsetTop | mInsetState.mInsetBottom) != 0) {
return true;
} else {
@@ -217,6 +218,11 @@
mInsetState.mDrawable.setColorFilter(cf);
}
+ @Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ mInsetState.mDrawable.setTint(tint, tintMode);
+ }
+
/** {@hide} */
@Override
public void setLayoutDirection(int layoutDirection) {
@@ -227,7 +233,7 @@
public int getOpacity() {
return mInsetState.mDrawable.getOpacity();
}
-
+
@Override
public boolean isStateful() {
return mInsetState.mDrawable.isStateful();
@@ -239,7 +245,12 @@
onBoundsChange(getBounds());
return changed;
}
-
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ return mInsetState.mDrawable.setLevel(level);
+ }
+
@Override
protected void onBoundsChange(Rect bounds) {
final Rect r = mTmpRect;
@@ -321,12 +332,12 @@
public Drawable newDrawable() {
return new InsetDrawable(this, null);
}
-
+
@Override
public Drawable newDrawable(Resources res) {
return new InsetDrawable(this, res);
}
-
+
@Override
public int getChangingConfigurations() {
return mChangingConfigurations;
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 27f0a9d..5cea7c9 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -16,12 +16,14 @@
package android.graphics.drawable;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
+import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
@@ -630,6 +632,15 @@
}
}
+ @Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ final ChildDrawable[] array = mLayerState.mChildren;
+ final int N = mLayerState.mNum;
+ for (int i = 0; i < N; i++) {
+ array[i].mDrawable.setTint(tint, tintMode);
+ }
+ }
+
/**
* Sets the opacity of this drawable directly, instead of collecting the
* states from the layers
diff --git a/graphics/java/android/graphics/drawable/QuantumProgressDrawable.java b/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java
similarity index 84%
rename from graphics/java/android/graphics/drawable/QuantumProgressDrawable.java
rename to graphics/java/android/graphics/drawable/MaterialProgressDrawable.java
index 675355c..c484094 100644
--- a/graphics/java/android/graphics/drawable/QuantumProgressDrawable.java
+++ b/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java
@@ -27,8 +27,10 @@
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Style;
+import android.graphics.PorterDuff.Mode;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -45,11 +47,11 @@
import java.util.ArrayList;
/**
- * Fancy progress indicator for Quantum theme.
+ * Fancy progress indicator for Material theme.
*
* TODO: Replace this class with something less ridiculous.
*/
-class QuantumProgressDrawable extends Drawable implements Animatable {
+class MaterialProgressDrawable extends Drawable implements Animatable {
private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
private static final TimeInterpolator END_CURVE_INTERPOLATOR = new EndCurveInterpolator();
private static final TimeInterpolator START_CURVE_INTERPOLATOR = new StartCurveInterpolator();
@@ -66,18 +68,19 @@
/** The indicator ring, used to manage animation state. */
private final Ring mRing;
- private QuantumProgressState mState;
+ private MaterialProgressState mState;
+ private PorterDuffColorFilter mTintFilter;
/** Canvas rotation in degrees. */
private float mRotation;
private boolean mMutated;
- public QuantumProgressDrawable() {
- this(new QuantumProgressState(null), null);
+ public MaterialProgressDrawable() {
+ this(new MaterialProgressState(null), null);
}
- private QuantumProgressDrawable(QuantumProgressState state, Theme theme) {
+ private MaterialProgressDrawable(MaterialProgressState state, Theme theme) {
mState = state;
if (theme != null && state.canApplyTheme()) {
applyTheme(theme);
@@ -91,7 +94,7 @@
}
private void initializeFromState() {
- final QuantumProgressState state = mState;
+ final MaterialProgressState state = mState;
final Ring ring = mRing;
ring.setStrokeWidth(state.mStrokeWidth);
@@ -106,27 +109,35 @@
float insets = minEdge / 2.0f - state.mInnerRadius;
ring.setInsets(insets);
}
+
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
}
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
- mState = new QuantumProgressState(mState);
+ mState = new MaterialProgressState(mState);
mMutated = true;
}
return this;
}
@Override
- protected boolean onStateChange(int[] state) {
- boolean changed = super.onStateChange(state);
+ protected boolean onStateChange(int[] stateSet) {
+ boolean changed = super.onStateChange(stateSet);
- final int color = mState.mColor.getColorForState(state, Color.TRANSPARENT);
+ final MaterialProgressState state = mState;
+ final int color = state.mColor.getColorForState(stateSet, Color.TRANSPARENT);
if (color != mRing.getColor()) {
mRing.setColor(color);
changed = true;
}
+ if (state.mTint != null && state.mTintMode != null) {
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ changed = true;
+ }
+
return changed;
}
@@ -138,8 +149,8 @@
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
- final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.QuantumProgressDrawable);
- super.inflateWithAttributes(r, parser, a, R.styleable.QuantumProgressDrawable_visible);
+ final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.MaterialProgressDrawable);
+ super.inflateWithAttributes(r, parser, a, R.styleable.MaterialProgressDrawable_visible);
updateStateFromTypedArray(a);
a.recycle();
@@ -149,25 +160,25 @@
@Override
public void applyTheme(Theme t) {
final TypedArray a = t.resolveAttributes(mState.mThemeAttrs,
- R.styleable.QuantumProgressDrawable);
+ R.styleable.MaterialProgressDrawable);
updateStateFromTypedArray(a);
a.recycle();
}
private void updateStateFromTypedArray(TypedArray a) {
- final QuantumProgressState state = mState;
+ final MaterialProgressState state = mState;
state.mThemeAttrs = a.extractThemeAttrs();
state.mWidth = a.getDimensionPixelSize(
- R.styleable.QuantumProgressDrawable_width, state.mWidth);
+ R.styleable.MaterialProgressDrawable_width, state.mWidth);
state.mHeight = a.getDimensionPixelSize(
- R.styleable.QuantumProgressDrawable_height, state.mHeight);
+ R.styleable.MaterialProgressDrawable_height, state.mHeight);
state.mInnerRadius = a.getDimension(
- R.styleable.QuantumProgressDrawable_innerRadius, state.mInnerRadius);
+ R.styleable.MaterialProgressDrawable_innerRadius, state.mInnerRadius);
state.mStrokeWidth = a.getDimension(
- R.styleable.QuantumProgressDrawable_thickness, state.mStrokeWidth);
+ R.styleable.MaterialProgressDrawable_thickness, state.mStrokeWidth);
- if (a.hasValue(R.styleable.QuantumProgressDrawable_color)) {
- state.mColor = a.getColorStateList(R.styleable.QuantumProgressDrawable_color);
+ if (a.hasValue(R.styleable.MaterialProgressDrawable_color)) {
+ state.mColor = a.getColorStateList(R.styleable.MaterialProgressDrawable_color);
}
}
@@ -223,11 +234,24 @@
return mRing.getColorFilter();
}
+ @Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ if (mState.mTint != tint || mState.mTintMode != tintMode) {
+ mState.mTint = tint;
+ mState.mTintMode = tintMode;
+
+ mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+ invalidateSelf();
+ }
+ }
+
+ @SuppressWarnings("unused")
private void setRotation(float rotation) {
mRotation = rotation;
invalidateSelf();
}
+ @SuppressWarnings("unused")
private float getRotation() {
return mRotation;
}
@@ -324,15 +348,17 @@
}
};
- private static class QuantumProgressState extends ConstantState {
+ private static class MaterialProgressState extends ConstantState {
private int[] mThemeAttrs = null;
private float mStrokeWidth = 5.0f;
private float mInnerRadius = -1.0f;
private int mWidth = -1;
private int mHeight = -1;
private ColorStateList mColor = ColorStateList.valueOf(Color.TRANSPARENT);
+ private ColorStateList mTint = null;
+ private Mode mTintMode = null;
- public QuantumProgressState(QuantumProgressState orig) {
+ public MaterialProgressState(MaterialProgressState orig) {
if (orig != null) {
mThemeAttrs = orig.mThemeAttrs;
mStrokeWidth = orig.mStrokeWidth;
@@ -340,6 +366,8 @@
mWidth = orig.mWidth;
mHeight = orig.mHeight;
mColor = orig.mColor;
+ mTint = orig.mTint;
+ mTintMode = orig.mTintMode;
}
}
@@ -360,7 +388,7 @@
@Override
public Drawable newDrawable(Resources res, Theme theme) {
- return new QuantumProgressDrawable(this, theme);
+ return new MaterialProgressDrawable(this, theme);
}
@Override
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 77ed29a..28335ea 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -327,25 +327,12 @@
@Override
public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) {
- mNinePatchState.mTint = tint;
- mNinePatchState.mTintMode = tintMode;
- computeTintFilter();
- invalidateSelf();
- }
-
- private void computeTintFilter() {
final NinePatchState state = mNinePatchState;
- if (state.mTint != null && state.mTintMode != null) {
- final int color = state.mTint.getColorForState(getState(), 0);
- if (mTintFilter != null) {
- mTintFilter.setColor(color);
- mTintFilter.setMode(state.mTintMode);
- } else {
- mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
- }
- } else {
- mTintFilter = null;
- }
+ state.mTint = tint;
+ state.mTintMode = tintMode;
+
+ mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+ invalidateSelf();
}
@Override
@@ -549,15 +536,10 @@
@Override
protected boolean onStateChange(int[] stateSet) {
- final ColorStateList tint = mNinePatchState.mTint;
- if (tint != null) {
- final int newColor = tint.getColorForState(stateSet, 0);
- final int oldColor = mTintFilter.getColor();
- if (oldColor != newColor) {
- mTintFilter.setColor(newColor);
- invalidateSelf();
- return true;
- }
+ final NinePatchState state = mNinePatchState;
+ if (state.mTint != null && state.mTintMode != null) {
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ return true;
}
return false;
@@ -659,6 +641,7 @@
*/
private NinePatchDrawable(NinePatchState state, Resources res, Theme theme) {
if (theme != null && state.canApplyTheme()) {
+ // If we need to apply a theme, implicitly mutate.
mNinePatchState = new NinePatchState(state);
applyTheme(theme);
} else {
@@ -688,7 +671,7 @@
mPadding = new Rect(state.mPadding);
}
- computeTintFilter();
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
setNinePatch(state.mNinePatch);
}
}
diff --git a/graphics/java/android/graphics/drawable/PaintDrawable.java b/graphics/java/android/graphics/drawable/PaintDrawable.java
index c71cda1..a82e7b9 100644
--- a/graphics/java/android/graphics/drawable/PaintDrawable.java
+++ b/graphics/java/android/graphics/drawable/PaintDrawable.java
@@ -35,7 +35,7 @@
public PaintDrawable(int color) {
getPaint().setColor(color);
}
-
+
/**
* Specify radius for the corners of the rectangle. If this is > 0, then the
* drawable is drawn in a round-rectangle, rather than a rectangle.
@@ -51,7 +51,7 @@
}
setCornerRadii(radii);
}
-
+
/**
* Specify radii for each of the 4 corners. For each corner, the array
* contains 2 values, [X_radius, Y_radius]. The corners are ordered
@@ -78,9 +78,9 @@
int radius = a.getDimensionPixelSize(
com.android.internal.R.styleable.DrawableCorners_radius, 0);
setCornerRadius(radius);
-
+
// now check of they have any per-corner radii
-
+
int topLeftRadius = a.getDimensionPixelSize(
com.android.internal.R.styleable.DrawableCorners_topLeftRadius, radius);
int topRightRadius = a.getDimensionPixelSize(
diff --git a/graphics/java/android/graphics/drawable/PictureDrawable.java b/graphics/java/android/graphics/drawable/PictureDrawable.java
index cb2d8f6..6dcda1f 100644
--- a/graphics/java/android/graphics/drawable/PictureDrawable.java
+++ b/graphics/java/android/graphics/drawable/PictureDrawable.java
@@ -25,7 +25,7 @@
/**
* Drawable subclass that wraps a Picture, allowing the picture to be used
- * whereever a Drawable is supported.
+ * wherever a Drawable is supported.
*/
public class PictureDrawable extends Drawable {
@@ -40,7 +40,7 @@
public PictureDrawable(Picture picture) {
mPicture = picture;
}
-
+
/**
* Return the picture associated with the drawable. May be null.
*
@@ -49,7 +49,7 @@
public Picture getPicture() {
return mPicture;
}
-
+
/**
* Associate a picture with this drawable. The picture may be null.
*
@@ -58,7 +58,7 @@
public void setPicture(Picture picture) {
mPicture = picture;
}
-
+
@Override
public void draw(Canvas canvas) {
if (mPicture != null) {
@@ -86,16 +86,16 @@
// not sure, so be safe
return PixelFormat.TRANSLUCENT;
}
-
+
@Override
public void setFilterBitmap(boolean filter) {}
-
+
@Override
public void setDither(boolean dither) {}
-
+
@Override
public void setColorFilter(ColorFilter colorFilter) {}
-
+
@Override
public void setAlpha(int alpha) {}
}
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 096e554..345400e 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -34,19 +34,22 @@
import java.util.ArrayList;
/**
- * Draws a Quantum Paper ripple.
+ * Draws a Material ripple.
*/
class Ripple {
private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
- private static final TimeInterpolator DECEL_INTERPOLATOR = new DecelerateInterpolator(4);
+ private static final TimeInterpolator DECEL_INTERPOLATOR = new LogInterpolator();
private static final float GLOBAL_SPEED = 1.0f;
private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024.0f * GLOBAL_SPEED;
- private static final float WAVE_TOUCH_UP_ACCELERATION = 3096.0f * GLOBAL_SPEED;
- private static final float WAVE_OPACITY_DECAY_VELOCITY = 1.9f / GLOBAL_SPEED;
- private static final float WAVE_OUTER_OPACITY_VELOCITY = 1.2f * GLOBAL_SPEED;
+ private static final float WAVE_TOUCH_UP_ACCELERATION = 3400.0f * GLOBAL_SPEED;
+ private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED;
+ private static final float WAVE_OUTER_OPACITY_VELOCITY_MAX = 4.5f * GLOBAL_SPEED;
+ private static final float WAVE_OUTER_OPACITY_VELOCITY_MIN = 1.5f * GLOBAL_SPEED;
+ private static final float WAVE_OUTER_SIZE_INFLUENCE_MAX = 200f;
+ private static final float WAVE_OUTER_SIZE_INFLUENCE_MIN = 40f;
- private static final long RIPPLE_ENTER_DELAY = 100;
+ private static final long RIPPLE_ENTER_DELAY = 80;
// Hardware animators.
private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>();
@@ -68,6 +71,8 @@
private float mStartingX;
private float mStartingY;
+ private float mClampedStartingX;
+ private float mClampedStartingY;
// Hardware rendering properties.
private CanvasProperty<Paint> mPropPaint;
@@ -112,6 +117,7 @@
public Ripple(RippleDrawable owner, Rect bounds, float startingX, float startingY) {
mOwner = owner;
mBounds = bounds;
+
mStartingX = startingX;
mStartingY = startingY;
}
@@ -131,6 +137,23 @@
mOuterX = 0;
mOuterY = 0;
mDensity = density;
+
+ clampStartingPosition();
+ }
+
+ private void clampStartingPosition() {
+ final float dX = mStartingX - mBounds.exactCenterX();
+ final float dY = mStartingY - mBounds.exactCenterY();
+ final float r = mOuterRadius;
+ if (dX * dX + dY * dY > r * r) {
+ // Point is outside the circle, clamp to the circumference.
+ final double angle = Math.atan2(dY, dX);
+ mClampedStartingX = (float) (Math.cos(angle) * r);
+ mClampedStartingY = (float) (Math.sin(angle) * r);
+ } else {
+ mClampedStartingX = mStartingX;
+ mClampedStartingY = mStartingY;
+ }
}
public void onHotspotBoundsChanged() {
@@ -138,6 +161,8 @@
final float halfWidth = mBounds.width() / 2.0f;
final float halfHeight = mBounds.height() / 2.0f;
mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
+
+ clampStartingPosition();
}
}
@@ -236,7 +261,7 @@
// Cache the paint alpha so we can restore it later.
final int paintAlpha = p.getAlpha();
- final int outerAlpha = (int) (255 * mOuterOpacity + 0.5f);
+ final int outerAlpha = (int) (paintAlpha * mOuterOpacity + 0.5f);
if (outerAlpha > 0 && mOuterRadius > 0) {
p.setAlpha(outerAlpha);
p.setStyle(Style.FILL);
@@ -244,11 +269,13 @@
hasContent = true;
}
- final int alpha = (int) (255 * mOpacity + 0.5f);
+ final int alpha = (int) (paintAlpha * mOpacity + 0.5f);
final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
if (alpha > 0 && radius > 0) {
- final float x = MathUtils.lerp(mStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
- final float y = MathUtils.lerp(mStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
+ final float x = MathUtils.lerp(
+ mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
+ final float y = MathUtils.lerp(
+ mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
p.setAlpha(alpha);
p.setStyle(Style.FILL);
c.drawCircle(x, y, radius, p);
@@ -277,6 +304,8 @@
public void move(float x, float y) {
mStartingX = x;
mStartingY = y;
+
+ clampStartingPosition();
}
/**
@@ -285,7 +314,7 @@
public void enter() {
final int radiusDuration = (int)
(1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
- final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY);
+ final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY_MIN);
final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radiusGravity", 1);
radius.setAutoCancel(true);
@@ -329,7 +358,6 @@
*/
public void exit() {
cancelSoftwareAnimations();
-
final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
final float remaining;
if (mAnimRadius != null && mAnimRadius.isRunning()) {
@@ -342,13 +370,23 @@
+ WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5);
final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
+ // Scale the outer max opacity and opacity velocity based
+ // on the size of the outer radius
+
+ float outerSizeInfluence = MathUtils.constrain(
+ (mOuterRadius - WAVE_OUTER_SIZE_INFLUENCE_MIN * mDensity)
+ / (WAVE_OUTER_SIZE_INFLUENCE_MAX * mDensity), 0, 1);
+ float outerOpacityVelocity = MathUtils.lerp(WAVE_OUTER_OPACITY_VELOCITY_MIN,
+ WAVE_OUTER_OPACITY_VELOCITY_MAX, outerSizeInfluence);
+
// Determine at what time the inner and outer opacity intersect.
// inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000
// outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000
+
final int outerInflection = Math.max(0, (int) (1000 * (mOpacity - mOuterOpacity)
- / (WAVE_OPACITY_DECAY_VELOCITY + WAVE_OUTER_OPACITY_VELOCITY) + 0.5f));
+ / (WAVE_OPACITY_DECAY_VELOCITY + outerOpacityVelocity) + 0.5f));
final int inflectionOpacity = (int) (255 * (mOuterOpacity + outerInflection
- * WAVE_OUTER_OPACITY_VELOCITY / 1000) + 0.5f);
+ * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f);
if (mCanUseHardware) {
exitHardware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity);
@@ -361,8 +399,10 @@
int inflectionOpacity) {
mPendingAnimations.clear();
- final float startX = MathUtils.lerp(mStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
- final float startY = MathUtils.lerp(mStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
+ final float startX = MathUtils.lerp(
+ mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX);
+ final float startY = MathUtils.lerp(
+ mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY);
final Paint outerPaint = new Paint();
outerPaint.setAntiAlias(true);
outerPaint.setColor(mColor);
@@ -578,4 +618,14 @@
removeSelf();
}
};
+
+ /**
+ * Interpolator with a smooth log deceleration
+ */
+ private static final class LogInterpolator implements TimeInterpolator {
+ @Override
+ public float getInterpolation(float input) {
+ return 1 - (float) Math.pow(400, -input * 1.4);
+ }
+ }
}
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 58f6eaa..0512ecc 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -48,22 +48,41 @@
* A touch feedback drawable may contain multiple child layers, including a
* special mask layer that is not drawn to the screen. A single layer may be set
* as the mask by specifying its android:id value as {@link android.R.id#mask}.
+ * <pre>
+ * <code><!-- A red ripple masked against an opaque rectangle. --/>
+ * <ripple android:color="#ffff0000">
+ * <item android:id="@android:id/mask"
+ * android:drawable="#ffffffff" />
+ * <ripple /></code>
+ * </pre>
* <p>
* If a mask layer is set, the ripple effect will be masked against that layer
- * before it is blended onto the composite of the remaining child layers.
+ * before it is drawn over the composite of the remaining child layers.
* <p>
- * If no mask layer is set, the ripple effect is simply blended onto the
- * composite of the child layers using the specified
- * {@link android.R.styleable#RippleDrawable_tintMode}.
+ * If no mask layer is set, the ripple effect is masked against the composite
+ * of the child layers.
+ * <pre>
+ * <code><!-- A blue ripple drawn atop a green rectangle. --/>
+ * <ripple android:color="#ff00ff00">
+ * <item android:drawable="#ff0000ff" />
+ * <ripple />
+ *
+ * <!-- A red ripple drawn atop a drawable resource. --/>
+ * <ripple android:color="#ff00ff00">
+ * <item android:drawable="@drawable/my_drawable" />
+ * <ripple /></code>
+ * </pre>
* <p>
* If no child layers or mask is specified and the ripple is set as a View
- * background, the ripple will be blended onto the first available parent
- * background within the View's hierarchy using the specified
- * {@link android.R.styleable#RippleDrawable_tintMode}. In this case, the
- * drawing region may extend outside of the Drawable bounds.
+ * background, the ripple will be drawn atop the first available parent
+ * background within the View's hierarchy. In this case, the drawing region
+ * may extend outside of the Drawable bounds.
+ * <pre>
+ * <code><!-- An unbounded green ripple. --/>
+ * <ripple android:color="#ff0000ff" /></code>
+ * </pre>
*
- * @attr ref android.R.styleable#DrawableStates_state_focused
- * @attr ref android.R.styleable#DrawableStates_state_pressed
+ * @attr ref android.R.styleable#RippleDrawable_color
*/
public class RippleDrawable extends LayerDrawable {
private static final String LOG_TAG = RippleDrawable.class.getSimpleName();
@@ -172,20 +191,24 @@
protected boolean onStateChange(int[] stateSet) {
super.onStateChange(stateSet);
+ // TODO: This would make more sense in a StateListDrawable.
boolean active = false;
+ boolean enabled = false;
final int N = stateSet.length;
for (int i = 0; i < N; i++) {
+ if (stateSet[i] == R.attr.state_enabled) {
+ enabled = true;
+ }
if (stateSet[i] == R.attr.state_focused
|| stateSet[i] == R.attr.state_pressed) {
active = true;
- break;
}
}
- setActive(active);
+ setActive(active && enabled);
// Update the paint color. Only applicable when animated in software.
- if (mRipplePaint != null && mState.mTint != null) {
- final ColorStateList stateList = mState.mTint;
+ if (mRipplePaint != null && mState.mColor != null) {
+ final ColorStateList stateList = mState.mColor;
final int newColor = stateList.getColorForState(stateSet, 0);
final int oldColor = mRipplePaint.getColor();
if (oldColor != newColor) {
@@ -244,10 +267,8 @@
return true;
}
- @Override
- public void setTint(ColorStateList tint, Mode tintMode) {
- mState.mTint = tint;
- mState.setTintMode(tintMode);
+ public void setColor(ColorStateList color) {
+ mState.mColor = color;
invalidateSelf();
}
@@ -308,22 +329,15 @@
// Extract the theme attributes, if any.
state.mTouchThemeAttrs = a.extractThemeAttrs();
- final ColorStateList tint = a.getColorStateList(R.styleable.RippleDrawable_tint);
- if (tint != null) {
- mState.mTint = tint;
+ final ColorStateList color = a.getColorStateList(R.styleable.RippleDrawable_color);
+ if (color != null) {
+ mState.mColor = color;
}
- final int tintMode = a.getInt(R.styleable.RippleDrawable_tintMode, -1);
- if (tintMode != -1) {
- mState.setTintMode(Drawable.parseTintMode(tintMode, Mode.SRC_ATOP));
- }
-
- mState.mPinned = a.getBoolean(R.styleable.RippleDrawable_pinned, mState.mPinned);
-
// If we're not waiting on a theme, verify required attributes.
- if (state.mTouchThemeAttrs == null && mState.mTint == null) {
+ if (state.mTouchThemeAttrs == null && mState.mColor == null) {
throw new XmlPullParserException(a.getPositionDescription() +
- ": <ripple> requires a valid tint attribute");
+ ": <ripple> requires a valid color attribute");
}
}
@@ -368,11 +382,6 @@
@Override
public void setHotspot(float x, float y) {
- if (mState.mPinned && !circleContains(mHotspotBounds, x, y)) {
- x = mHotspotBounds.exactCenterX();
- y = mHotspotBounds.exactCenterY();
- }
-
if (mHotspot == null) {
mHotspot = new Ripple(this, mHotspotBounds, x, y);
@@ -384,18 +393,6 @@
}
}
- private boolean circleContains(Rect bounds, float x, float y) {
- final float pX = bounds.exactCenterX() - x;
- final float pY = bounds.exactCenterY() - y;
- final double pointRadius = Math.sqrt(pX * pX + pY * pY);
-
- final float bX = bounds.width() / 2.0f;
- final float bY = bounds.height() / 2.0f;
- final double boundsRadius = Math.sqrt(bX * bX + bY * bY);
-
- return pointRadius < boundsRadius;
- }
-
/**
* Creates an active hotspot at the specified location.
*/
@@ -413,7 +410,7 @@
mHotspot = new Ripple(this, mHotspotBounds, x, y);
}
- final int color = mState.mTint.getColorForState(getState(), Color.TRANSPARENT);
+ final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
mHotspot.setup(mState.mMaxRadius, color, mDensity);
mHotspot.enter();
@@ -471,16 +468,23 @@
@Override
public void draw(Canvas canvas) {
- final Rect bounds = isProjected() ? getDirtyBounds() : getBounds();
+ final boolean isProjected = isProjected();
+ final boolean hasMask = mMask != null;
+ final boolean drawNonMaskContent = mLayerState.mNum > (hasMask ? 1 : 0);
+ final boolean drawMask = hasMask && mMask.getOpacity() != PixelFormat.OPAQUE;
+ final Rect bounds = isProjected ? getDirtyBounds() : getBounds();
- // Draw the content into a layer first.
- final int contentLayer = drawContentLayer(canvas, bounds, SRC_OVER);
+ // If we have content, draw it into a layer first.
+ final int contentLayer = drawNonMaskContent ?
+ drawContentLayer(canvas, bounds, SRC_OVER) : -1;
- // Next, draw the ripples into a layer.
- final int rippleLayer = drawRippleLayer(canvas, bounds, mState.mTintXfermode);
+ // Next, try to draw the ripples (into a layer if necessary). If we need
+ // to mask against the underlying content, set the xfermode to SRC_ATOP.
+ final PorterDuffXfermode xfermode = (hasMask || !drawNonMaskContent) ? SRC_OVER : SRC_ATOP;
+ final int rippleLayer = drawRippleLayer(canvas, bounds, xfermode);
- // If we have ripples, draw the masking layer.
- if (rippleLayer >= 0) {
+ // If we have ripples and a non-opaque mask, draw the masking layer.
+ if (rippleLayer >= 0 && drawMask) {
drawMaskingLayer(canvas, bounds, DST_IN);
}
@@ -524,17 +528,27 @@
}
private int drawContentLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) {
+ final ChildDrawable[] array = mLayerState.mChildren;
final int count = mLayerState.mNum;
- if (count == 0 || (mMask != null && count == 1)) {
- return -1;
+
+ // We don't need a layer if we don't expect to draw any ripples, we have
+ // an explicit mask, or if the non-mask content is all opaque.
+ boolean needsLayer = false;
+ if (mAnimatingRipplesCount > 0 && mMask == null) {
+ for (int i = 0; i < count; i++) {
+ if (array[i].mId != R.id.mask
+ && array[i].mDrawable.getOpacity() != PixelFormat.OPAQUE) {
+ needsLayer = true;
+ break;
+ }
+ }
}
final Paint maskingPaint = getMaskingPaint(mode);
- final int restoreToCount = canvas.saveLayer(bounds.left, bounds.top,
- bounds.right, bounds.bottom, maskingPaint);
+ final int restoreToCount = needsLayer ? canvas.saveLayer(bounds.left, bounds.top,
+ bounds.right, bounds.bottom, maskingPaint) : -1;
// Draw everything except the mask.
- final ChildDrawable[] array = mLayerState.mChildren;
for (int i = 0; i < count; i++) {
if (array[i].mId != R.id.mask) {
array[i].mDrawable.draw(canvas);
@@ -553,20 +567,21 @@
// Separate the ripple color and alpha channel. The alpha will be
// applied when we merge the ripples down to the canvas.
final int rippleARGB;
- if (mState.mTint != null) {
- rippleARGB = mState.mTint.getColorForState(getState(), Color.TRANSPARENT);
+ if (mState.mColor != null) {
+ rippleARGB = mState.mColor.getColorForState(getState(), Color.TRANSPARENT);
} else {
rippleARGB = Color.TRANSPARENT;
}
- final int rippleAlpha = Color.alpha(rippleARGB);
- final int rippleColor = rippleARGB | (0xFF << 24);
if (mRipplePaint == null) {
mRipplePaint = new Paint();
mRipplePaint.setAntiAlias(true);
}
+
+ final int rippleAlpha = Color.alpha(rippleARGB);
final Paint ripplePaint = mRipplePaint;
- ripplePaint.setColor(rippleColor);
+ ripplePaint.setColor(rippleARGB);
+ ripplePaint.setAlpha(0xFF);
boolean drewRipples = false;
int restoreToCount = -1;
@@ -584,7 +599,6 @@
maskingPaint.setAlpha(rippleAlpha);
restoreToCount = canvas.saveLayer(bounds.left, bounds.top,
bounds.right, bounds.bottom, maskingPaint);
- maskingPaint.setAlpha(255);
restoreTranslate = canvas.save();
// Translate the canvas to the current hotspot bounds.
@@ -609,18 +623,13 @@
}
private int drawMaskingLayer(Canvas canvas, Rect bounds, PorterDuffXfermode mode) {
- final Drawable mask = mMask;
- if (mask == null) {
- return -1;
- }
-
final int restoreToCount = canvas.saveLayer(bounds.left, bounds.top,
bounds.right, bounds.bottom, getMaskingPaint(mode));
// Ensure that DST_IN blends using the entire layer.
canvas.drawColor(Color.TRANSPARENT);
- mask.draw(canvas);
+ mMask.draw(canvas);
return restoreToCount;
}
@@ -630,6 +639,7 @@
mMaskingPaint = new Paint();
}
mMaskingPaint.setXfermode(xfermode);
+ mMaskingPaint.setAlpha(0xFF);
return mMaskingPaint;
}
@@ -663,31 +673,19 @@
static class RippleState extends LayerState {
int[] mTouchThemeAttrs;
- ColorStateList mTint = null;
- PorterDuffXfermode mTintXfermode = SRC_ATOP;
+ ColorStateList mColor = null;
int mMaxRadius = RADIUS_AUTO;
- boolean mPinned = false;
public RippleState(RippleState orig, RippleDrawable owner, Resources res) {
super(orig, owner, res);
if (orig != null) {
mTouchThemeAttrs = orig.mTouchThemeAttrs;
- mTint = orig.mTint;
- mTintXfermode = orig.mTintXfermode;
+ mColor = orig.mColor;
mMaxRadius = orig.mMaxRadius;
- mPinned = orig.mPinned;
}
}
- public void setTintMode(Mode mode) {
- mTintXfermode = new PorterDuffXfermode(mode);
- }
-
- public PorterDuffXfermode getTintXfermode() {
- return mTintXfermode;
- }
-
@Override
public boolean canApplyTheme() {
return mTouchThemeAttrs != null || super.canApplyTheme();
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 06aeb98..8f8fa98 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -22,6 +22,8 @@
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Rect;
+import android.graphics.PorterDuff.Mode;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
@@ -137,6 +139,11 @@
}
@Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ mState.mDrawable.setTint(tint, tintMode);
+ }
+
+ @Override
public int getOpacity() {
return mState.mDrawable.getOpacity();
}
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index f090c11..46c92fe 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -19,10 +19,12 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
import android.graphics.*;
+import android.graphics.PorterDuff.Mode;
import android.view.Gravity;
import android.util.AttributeSet;
@@ -188,6 +190,11 @@
}
@Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ mScaleState.mDrawable.setTint(tint, tintMode);
+ }
+
+ @Override
public int getOpacity() {
return mScaleState.mDrawable.getOpacity();
}
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 024f77c..beb300d 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -24,6 +24,7 @@
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
@@ -32,6 +33,7 @@
import android.content.res.Resources.Theme;
import android.util.AttributeSet;
+import com.android.internal.R;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -74,7 +76,7 @@
* ShapeDrawable constructor.
*/
public ShapeDrawable() {
- this((ShapeState) null);
+ this(new ShapeState(null), null, null);
}
/**
@@ -83,20 +85,11 @@
* @param s the Shape that this ShapeDrawable should be
*/
public ShapeDrawable(Shape s) {
- this((ShapeState) null);
+ this(new ShapeState(null), null, null);
mShapeState.mShape = s;
}
- private ShapeDrawable(ShapeState state) {
- mShapeState = new ShapeState(state);
-
- if (state != null && state.mTint != null) {
- final int color = state.mTint.getColorForState(getState(), 0);
- mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
- }
- }
-
/**
* Returns the Shape of this ShapeDrawable.
*/
@@ -292,31 +285,13 @@
}
@Override
- public void setTint(ColorStateList tint, Mode tintMode) {
- if (mShapeState.mTint != tint || mShapeState.mTintMode != tintMode) {
- mShapeState.mTint = tint;
- mShapeState.mTintMode = tintMode;
- updateTintFilter();
- invalidateSelf();
- }
- }
+ public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) {
+ final ShapeState state = mShapeState;
+ state.mTint = tint;
+ state.mTintMode = tintMode;
- /**
- * Ensures the tint filter is consistent with the current tint color and
- * mode.
- */
- private void updateTintFilter() {
- final ColorStateList tint = mShapeState.mTint;
- final Mode tintMode = mShapeState.mTintMode;
- if (tint != null && tintMode != null) {
- if (mTintFilter == null) {
- mTintFilter = new PorterDuffColorFilter(0, tintMode);
- } else {
- mTintFilter.setMode(tintMode);
- }
- } else {
- mTintFilter = null;
- }
+ mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+ invalidateSelf();
}
@Override
@@ -357,17 +332,11 @@
@Override
protected boolean onStateChange(int[] stateSet) {
- final ColorStateList tint = mShapeState.mTint;
- if (tint != null) {
- final int newColor = tint.getColorForState(stateSet, 0);
- final int oldColor = mTintFilter.getColor();
- if (oldColor != newColor) {
- mTintFilter.setColor(newColor);
- invalidateSelf();
- return true;
- }
+ final ShapeState state = mShapeState;
+ if (state.mTint != null && state.mTintMode != null) {
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ return true;
}
-
return false;
}
@@ -408,20 +377,8 @@
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs, theme);
- TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.ShapeDrawable);
-
- int color = mShapeState.mPaint.getColor();
- color = a.getColor(com.android.internal.R.styleable.ShapeDrawable_color, color);
- mShapeState.mPaint.setColor(color);
-
- boolean dither = a.getBoolean(com.android.internal.R.styleable.ShapeDrawable_dither, false);
- mShapeState.mPaint.setDither(dither);
-
- setIntrinsicWidth((int)
- a.getDimension(com.android.internal.R.styleable.ShapeDrawable_width, 0f));
- setIntrinsicHeight((int)
- a.getDimension(com.android.internal.R.styleable.ShapeDrawable_height, 0f));
-
+ final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ShapeDrawable);
+ updateStateFromTypedArray(a);
a.recycle();
int type;
@@ -441,6 +398,38 @@
}
}
+ @Override
+ public void applyTheme(Theme t) {
+ super.applyTheme(t);
+
+ final ShapeState state = mShapeState;
+ if (state == null || state.mThemeAttrs == null) {
+ return;
+ }
+
+ final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ShapeDrawable);
+ updateStateFromTypedArray(a);
+ a.recycle();
+ }
+
+ private void updateStateFromTypedArray(TypedArray a) {
+ final ShapeState state = mShapeState;
+ final Paint paint = state.mPaint;
+
+ int color = paint.getColor();
+ color = a.getColor(R.styleable.ShapeDrawable_color, color);
+ paint.setColor(color);
+
+ boolean dither = paint.isDither();
+ dither = a.getBoolean(R.styleable.ShapeDrawable_dither, dither);
+ paint.setDither(dither);
+
+ setIntrinsicWidth((int) a.getDimension(
+ R.styleable.ShapeDrawable_width, state.mIntrinsicWidth));
+ setIntrinsicHeight((int) a.getDimension(
+ R.styleable.ShapeDrawable_height, state.mIntrinsicHeight));
+ }
+
private void updateShape() {
if (mShapeState.mShape != null) {
final Rect r = getBounds();
@@ -498,6 +487,7 @@
* Defines the intrinsic properties of this ShapeDrawable's Shape.
*/
final static class ShapeState extends ConstantState {
+ int[] mThemeAttrs;
int mChangingConfigurations;
Paint mPaint;
Shape mShape;
@@ -511,6 +501,7 @@
ShapeState(ShapeState orig) {
if (orig != null) {
+ mThemeAttrs = orig.mThemeAttrs;
mPaint = orig.mPaint;
mShape = orig.mShape;
mTint = orig.mTint;
@@ -526,13 +517,23 @@
}
@Override
+ public boolean canApplyTheme() {
+ return mThemeAttrs != null;
+ }
+
+ @Override
public Drawable newDrawable() {
- return new ShapeDrawable(this);
+ return new ShapeDrawable(this, null, null);
}
@Override
public Drawable newDrawable(Resources res) {
- return new ShapeDrawable(this);
+ return new ShapeDrawable(this, res, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res, Theme theme) {
+ return new ShapeDrawable(this, res, theme);
}
@Override
@@ -541,6 +542,17 @@
}
}
+ private ShapeDrawable(ShapeState state, Resources res, Theme theme) {
+ if (theme != null && state.canApplyTheme()) {
+ mShapeState = new ShapeState(state);
+ applyTheme(theme);
+ } else {
+ mShapeState = state;
+ }
+
+ mTintFilter = updateTintFilter(mTintFilter, mShapeState.mTint, mShapeState.mTintMode);
+ }
+
/**
* Base class defines a factory object that is called each time the drawable
* is resized (has a new width or height). Its resize() method returns a
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index b2fac9b..f359fdd 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -235,10 +235,10 @@
public Drawable getStateDrawable(int index) {
return mStateListState.getChild(index);
}
-
+
/**
* Gets the index of the drawable with the provided state set.
- *
+ *
* @param stateSet the state set to look up
* @return the index of the provided state set, or -1 if not found
* @hide pending API council
@@ -248,7 +248,7 @@
public int getStateDrawableIndex(int[] stateSet) {
return mStateListState.indexOfStateSet(stateSet);
}
-
+
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index 622e90b..4380ca4e 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -42,20 +42,20 @@
public class TransitionDrawable extends LayerDrawable implements Drawable.Callback {
/**
- * A transition is about to start.
+ * A transition is about to start.
*/
private static final int TRANSITION_STARTING = 0;
-
+
/**
* The transition has started and the animation is in progress
*/
private static final int TRANSITION_RUNNING = 1;
-
+
/**
* No transition will be applied
*/
private static final int TRANSITION_NONE = 2;
-
+
/**
* The current state of the transition. One of {@link #TRANSITION_STARTING},
* {@link #TRANSITION_RUNNING} and {@link #TRANSITION_NONE}
@@ -101,10 +101,10 @@
LayerState createConstantState(LayerState state, Resources res) {
return new TransitionState((TransitionState) state, this, res);
}
-
+
/**
* Begin the second layer on top of the first layer.
- *
+ *
* @param durationMillis The length of the transition in milliseconds
*/
public void startTransition(int durationMillis) {
@@ -116,7 +116,7 @@
mTransitionState = TRANSITION_STARTING;
invalidateSelf();
}
-
+
/**
* Show only the first layer.
*/
@@ -184,7 +184,7 @@
}
break;
}
-
+
final int alpha = mAlpha;
final boolean crossFade = mCrossFade;
final ChildDrawable[] array = mLayerState.mChildren;
@@ -217,7 +217,7 @@
d.draw(canvas);
d.setAlpha(0xFF);
}
-
+
if (!done) {
invalidateSelf();
}
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index c6c5b31..c3c1bca 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -14,6 +14,7 @@
package android.graphics.drawable;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
@@ -25,8 +26,11 @@
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.PixelFormat;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.PorterDuff.Mode;
+import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
@@ -40,7 +44,6 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.Stack;
/**
@@ -135,6 +138,10 @@
private final VectorDrawableState mVectorState;
+ private final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
+
+ private PorterDuffColorFilter mTintFilter;
+
public VectorDrawable() {
mVectorState = new VectorDrawableState(null);
}
@@ -145,6 +152,13 @@
if (theme != null && canApplyTheme()) {
applyTheme(theme);
}
+
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
+ }
+
+ Object getTargetByName(String name) {
+ return mVGTargetsMap.get(name);
}
@Override
@@ -162,6 +176,11 @@
}
@Override
+ public int getAlpha() {
+ return mVectorState.mVPathRenderer.getRootAlpha();
+ }
+
+ @Override
public void setAlpha(int alpha) {
if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) {
mVectorState.mVPathRenderer.setRootAlpha(alpha);
@@ -171,11 +190,46 @@
@Override
public void setColorFilter(ColorFilter colorFilter) {
- mVectorState.mVPathRenderer.setColorFilter(colorFilter);
+ final VectorDrawableState state = mVectorState;
+ if (colorFilter != null) {
+ // Color filter overrides tint.
+ mTintFilter = null;
+ } else if (state.mTint != null && state.mTintMode != null) {
+ // Restore the tint filter, if we need one.
+ final int color = state.mTint.getColorForState(getState(), Color.TRANSPARENT);
+ mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
+ colorFilter = mTintFilter;
+ }
+
+ state.mVPathRenderer.setColorFilter(colorFilter);
invalidateSelf();
}
@Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ final VectorDrawableState state = mVectorState;
+ if (state.mTint != tint || state.mTintMode != tintMode) {
+ state.mTint = tint;
+ state.mTintMode = tintMode;
+
+ mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+ mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ protected boolean onStateChange(int[] stateSet) {
+ final VectorDrawableState state = mVectorState;
+ if (state.mTint != null && state.mTintMode != null) {
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@@ -302,6 +356,9 @@
final VPath path = new VPath();
path.inflate(res, attrs, theme);
currentGroup.add(path);
+ if (path.getPathName() != null) {
+ mVGTargetsMap.put(path.getPathName(), path);
+ }
noPathTag = false;
} else if (SHAPE_SIZE.equals(tagName)) {
pathRenderer.parseSize(res, attrs);
@@ -314,6 +371,9 @@
newChildGroup.inflate(res, attrs, theme);
currentGroup.mChildGroupList.add(newChildGroup);
groupStack.push(newChildGroup);
+ if (newChildGroup.getGroupName() != null) {
+ mVGTargetsMap.put(newChildGroup.getGroupName(), newChildGroup);
+ }
noGroupTag = false;
}
} else if (eventType == XmlPullParser.END_TAG) {
@@ -363,7 +423,7 @@
indent += " ";
}
// Print the current node
- Log.v(LOGTAG, indent + "current group is :" + currentGroup.getName()
+ Log.v(LOGTAG, indent + "current group is :" + currentGroup.getGroupName()
+ " rotation is " + currentGroup.mRotate);
Log.v(LOGTAG, indent + "matrix is :" + currentGroup.getLocalMatrix().toString());
// Then print all the children
@@ -380,6 +440,8 @@
int mChangingConfigurations;
VPathRenderer mVPathRenderer;
Rect mPadding;
+ ColorStateList mTint;
+ Mode mTintMode;
public VectorDrawableState(VectorDrawableState copy) {
if (copy != null) {
@@ -387,6 +449,8 @@
// TODO: Make sure the constant state are handled correctly.
mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
mPadding = new Rect(copy.mPadding);
+ mTint = copy.mTint;
+ mTintMode = copy.mTintMode;
}
}
@@ -672,8 +736,7 @@
}
- private static class VGroup {
- private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
+ static class VGroup {
private final ArrayList<VPath> mPathList = new ArrayList<VPath>();
private final ArrayList<VGroup> mChildGroupList = new ArrayList<VGroup>();
@@ -694,10 +757,98 @@
private int[] mThemeAttrs;
- private String mName = null;
+ private String mGroupName = null;
- public String getName() {
- return mName;
+ /* Getter and Setter */
+ public float getRotation() {
+ return mRotate;
+ }
+
+ public void setRotation(float rotation) {
+ if (rotation != mRotate) {
+ mRotate = rotation;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getPivotX() {
+ return mPivotX;
+ }
+
+ public void setPivotX(float pivotX) {
+ if (pivotX != mPivotX) {
+ mPivotX = pivotX;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getPivotY() {
+ return mPivotY;
+ }
+
+ public void setPivotY(float pivotY) {
+ if (pivotY != mPivotY) {
+ mPivotY = pivotY;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getScaleX() {
+ return mScaleX;
+ }
+
+ public void setScaleX(float scaleX) {
+ if (scaleX != mScaleX) {
+ mScaleX = scaleX;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getScaleY() {
+ return mScaleY;
+ }
+
+ public void setScaleY(float scaleY) {
+ if (scaleY != mScaleY) {
+ mScaleY = scaleY;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getTranslateX() {
+ return mTranslateX;
+ }
+
+ public void setTranslateX(float translateX) {
+ if (translateX != mTranslateX) {
+ mTranslateX = translateX;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getTranslateY() {
+ return mTranslateY;
+ }
+
+ public void setTranslateY(float translateY) {
+ if (translateY != mTranslateY) {
+ mTranslateY = translateY;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getAlpha() {
+ return mGroupAlpha;
+ }
+
+ public void setAlpha(float groupAlpha) {
+ if (groupAlpha != mGroupAlpha) {
+ mGroupAlpha = groupAlpha;
+ }
+ }
+
+ public String getGroupName() {
+ return mGroupName;
}
public Matrix getLocalMatrix() {
@@ -705,8 +856,6 @@
}
public void add(VPath path) {
- String id = path.getID();
- mVGPathMap.put(id, path);
mPathList.add(path);
}
@@ -732,7 +881,7 @@
mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha);
updateLocalMatrix();
if (a.hasValue(R.styleable.VectorDrawableGroup_name)) {
- mName = a.getString(R.styleable.VectorDrawableGroup_name);
+ mGroupName = a.getString(R.styleable.VectorDrawableGroup_name);
}
a.recycle();
}
@@ -774,7 +923,7 @@
}
if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_name] == 0) {
- mName = a.getString(R.styleable.VectorDrawableGroup_name);
+ mGroupName = a.getString(R.styleable.VectorDrawableGroup_name);
}
if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_alpha] == 0) {
@@ -805,19 +954,15 @@
}
- private static class VPath {
- private static final int MAX_STATES = 10;
-
+ static class VPath {
private int[] mThemeAttrs;
int mStrokeColor = 0;
float mStrokeWidth = 0;
float mStrokeOpacity = Float.NaN;
-
int mFillColor = Color.BLACK;
int mFillRule;
float mFillOpacity = Float.NaN;
-
float mTrimPathStart = 0;
float mTrimPathEnd = 1;
float mTrimPathOffset = 0;
@@ -828,7 +973,7 @@
float mStrokeMiterlimit = 4;
private VNode[] mNode = null;
- private String mId;
+ private String mPathName;
public VPath() {
// Empty constructor.
@@ -841,8 +986,8 @@
}
}
- public String getID() {
- return mId;
+ public String getPathName() {
+ return mPathName;
}
private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
@@ -871,6 +1016,71 @@
}
}
+ /* Setters and Getters */
+ int getStroke() {
+ return mStrokeColor;
+ }
+
+ void setStroke(int strokeColor) {
+ mStrokeColor = strokeColor;
+ }
+
+ float getStrokeWidth() {
+ return mStrokeWidth;
+ }
+
+ void setStrokeWidth(float strokeWidth) {
+ mStrokeWidth = strokeWidth;
+ }
+
+ float getStrokeOpacity() {
+ return mStrokeOpacity;
+ }
+
+ void setStrokeOpacity(float strokeOpacity) {
+ mStrokeOpacity = strokeOpacity;
+ }
+
+ int getFill() {
+ return mFillColor;
+ }
+
+ void setFill(int fillColor) {
+ mFillColor = fillColor;
+ }
+
+ float getFillOpacity() {
+ return mFillOpacity;
+ }
+
+ void setFillOpacity(float fillOpacity) {
+ mFillOpacity = fillOpacity;
+ }
+
+ float getTrimPathStart() {
+ return mTrimPathStart;
+ }
+
+ void setTrimPathStart(float trimPathStart) {
+ mTrimPathStart = trimPathStart;
+ }
+
+ float getTrimPathEnd() {
+ return mTrimPathEnd;
+ }
+
+ void setTrimPathEnd(float trimPathEnd) {
+ mTrimPathEnd = trimPathEnd;
+ }
+
+ float getTrimPathOffset() {
+ return mTrimPathOffset;
+ }
+
+ void setTrimPathOffset(float trimPathOffset) {
+ mTrimPathOffset = trimPathOffset;
+ }
+
public void inflate(Resources r, AttributeSet attrs, Theme theme) {
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
final int[] themeAttrs = a.extractThemeAttrs();
@@ -883,7 +1093,7 @@
}
if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) {
- mId = a.getString(R.styleable.VectorDrawablePath_name);
+ mPathName = a.getString(R.styleable.VectorDrawablePath_name);
}
if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) {
@@ -966,7 +1176,7 @@
mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
if (a.hasValue(R.styleable.VectorDrawablePath_name)) {
- mId = a.getString(R.styleable.VectorDrawablePath_name);
+ mPathName = a.getString(R.styleable.VectorDrawablePath_name);
}
if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) {
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index 21d6caa..4a823cc 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -35,7 +35,7 @@
/**
* This provides the required parameters needed for initializing the
* {@code KeyPairGenerator} that works with
- * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore
+ * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
* facility</a>. The Android KeyStore facility is accessed through a
* {@link java.security.KeyPairGenerator} API using the {@code AndroidKeyStore}
* provider. The {@code context} passed in may be used to pop up some UI to ask
@@ -306,7 +306,7 @@
* Builder class for {@link KeyPairGeneratorSpec} objects.
* <p>
* This will build a parameter spec for use with the <a href="{@docRoot}
- * guide/topics/security/keystore.html">Android KeyStore facility</a>.
+ * training/articles/keystore.html">Android KeyStore facility</a>.
* <p>
* The required fields must be filled in with the builder.
* <p>
diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
index b71efc4..2eeb6ad 100644
--- a/keystore/java/android/security/KeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -24,7 +24,7 @@
/**
* This provides the optional parameters that can be specified for
* {@code KeyStore} entries that work with
- * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore
+ * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
* facility</a>. The Android KeyStore facility is accessed through a
* {@link java.security.KeyStore} API using the {@code AndroidKeyStore}
* provider. The {@code context} passed in may be used to pop up some UI to ask
@@ -67,7 +67,7 @@
* Builder class for {@link KeyStoreParameter} objects.
* <p>
* This will build protection parameters for use with the
- * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore
+ * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
* facility</a>.
* <p>
* This can be used to require that KeyStore entries be stored encrypted.
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 91dda75..1b3f1fd 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -1768,6 +1768,7 @@
}
mergeInfoLocked(pMergedInfo, pContents);
+ delete pContents;
return true;
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 7d4da01..a4b78a6 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3221,7 +3221,7 @@
header->header = (const ResTable_header*) resHeader;
mHeaders.add(header);
- return NO_ERROR;
+ return (mError=NO_ERROR);
}
status_t ResTable::addInternal(const void* data, size_t size, const int32_t cookie,
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index c1af5f5..937b7c6 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -44,18 +44,18 @@
* @param shadowVertexBuffer Return an floating point array of (x, y, a)
* triangle strips mode.
*/
-VertexBufferMode AmbientShadow::createAmbientShadow(bool isCasterOpaque,
+void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
const Vector3* vertices, int vertexCount, const Vector3& centroid3d,
float heightFactor, float geomFactor, VertexBuffer& shadowVertexBuffer) {
const int rays = SHADOW_RAY_COUNT;
- VertexBufferMode mode = kVertexBufferMode_OnePolyRingShadow;
+ VertexBuffer::Mode mode = VertexBuffer::kOnePolyRingShadow;
// Validate the inputs.
if (vertexCount < 3 || heightFactor <= 0 || rays <= 0
|| geomFactor <= 0) {
#if DEBUG_SHADOW
ALOGW("Invalid input for createAmbientShadow(), early return!");
#endif
- return mode; // vertex buffer is empty, so any mode doesn't matter.
+ return;
}
Vector<Vector2> dir; // TODO: use C++11 unique_ptr
@@ -127,7 +127,7 @@
// If caster isn't opaque, we need to to fill the umbra by storing the umbra's
// centroid in the innermost ring of vertices.
if (!isCasterOpaque) {
- mode = kVertexBufferMode_TwoPolyRingShadow;
+ mode = VertexBuffer::kTwoPolyRingShadow;
float centroidAlpha = 1.0 / (1 + centroid3d.z * heightFactor);
AlphaVertex centroidXYA;
AlphaVertex::set(¢roidXYA, centroid2d.x, centroid2d.y, centroidAlpha);
@@ -135,6 +135,7 @@
shadowVertices[2 * rays + rayIndex] = centroidXYA;
}
}
+ shadowVertexBuffer.setMode(mode);
#if DEBUG_SHADOW
for (int i = 0; i < SHADOW_VERTEX_COUNT; i++) {
@@ -142,7 +143,6 @@
shadowVertices[i].y, shadowVertices[i].alpha);
}
#endif
- return mode;
}
/**
diff --git a/libs/hwui/AmbientShadow.h b/libs/hwui/AmbientShadow.h
index 451bfbe..68df246 100644
--- a/libs/hwui/AmbientShadow.h
+++ b/libs/hwui/AmbientShadow.h
@@ -35,7 +35,7 @@
*/
class AmbientShadow {
public:
- static VertexBufferMode createAmbientShadow(bool isCasterOpaque, const Vector3* poly,
+ static void createAmbientShadow(bool isCasterOpaque, const Vector3* poly,
int polyLength, const Vector3& centroid3d, float heightFactor,
float geomFactor, VertexBuffer& shadowVertexBuffer);
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index cc62170..02e85fe 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -52,6 +52,7 @@
SpotShadow.cpp \
StatefulBaseRenderer.cpp \
Stencil.cpp \
+ TessellationCache.cpp \
Texture.cpp \
TextureCache.cpp \
TextDropShadowCache.cpp
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 77ef637..402f28b 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -273,6 +273,8 @@
gradientCache.getSize(), gradientCache.getMaxSize());
log.appendFormat(" PathCache %8d / %8d\n",
pathCache.getSize(), pathCache.getMaxSize());
+ log.appendFormat(" TessellationCache %8d / %8d\n",
+ tessellationCache.getSize(), tessellationCache.getMaxSize());
log.appendFormat(" TextDropShadowCache %8d / %8d\n", dropShadowCache.getSize(),
dropShadowCache.getMaxSize());
log.appendFormat(" PatchCache %8d / %8d\n",
@@ -295,6 +297,7 @@
total += renderBufferCache.getSize();
total += gradientCache.getSize();
total += pathCache.getSize();
+ total += tessellationCache.getSize();
total += dropShadowCache.getSize();
total += patchCache.getSize();
for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
@@ -358,6 +361,7 @@
fontRenderer->flush();
textureCache.flush();
pathCache.clear();
+ tessellationCache.clear();
// fall through
case kFlushMode_Layers:
layerCache.clear();
@@ -561,11 +565,8 @@
// call, any texture operation will be performed on the default
// texture (name=0)
- for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
- if (mBoundTextures[i] == texture) {
- mBoundTextures[i] = 0;
- }
- }
+ unbindTexture(texture);
+
glDeleteTextures(1, &texture);
}
@@ -573,6 +574,14 @@
memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint));
}
+void Caches::unbindTexture(GLuint texture) {
+ for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
+ if (mBoundTextures[i] == texture) {
+ mBoundTextures[i] = 0;
+ }
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
// Scissor
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 5367663..83a5d9a 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -43,6 +43,7 @@
#include "PatchCache.h"
#include "ProgramCache.h"
#include "PathCache.h"
+#include "TessellationCache.h"
#include "TextDropShadowCache.h"
#include "FboCache.h"
#include "ResourceCache.h"
@@ -260,6 +261,11 @@
void resetBoundTextures();
/**
+ * Clear the cache of bound textures.
+ */
+ void unbindTexture(GLuint texture);
+
+ /**
* Sets the scissor for the current surface.
*/
bool setScissor(GLint x, GLint y, GLint width, GLint height);
@@ -326,6 +332,7 @@
ProgramCache programCache;
PathCache pathCache;
PatchCache patchCache;
+ TessellationCache tessellationCache;
TextDropShadowCache dropShadowCache;
FboCache fboCache;
ResourceCache resourceCache;
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 8aa8c92..77d16ab 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -26,8 +26,25 @@
namespace android {
namespace uirenderer {
+NullDamageAccumulator NullDamageAccumulator::sInstance;
+
+NullDamageAccumulator* NullDamageAccumulator::instance() {
+ return &sInstance;
+}
+
+enum TransformType {
+ TransformInvalid = 0,
+ TransformRenderNode,
+ TransformMatrix4,
+ TransformNone,
+};
+
struct DirtyStack {
- const RenderNode* node;
+ TransformType type;
+ union {
+ const RenderNode* renderNode;
+ const Matrix4* matrix4;
+ };
// When this frame is pop'd, this rect is mapped through the above transform
// and applied to the previous (aka parent) frame
SkRect pendingDirty;
@@ -40,9 +57,10 @@
memset(mHead, 0, sizeof(DirtyStack));
// Create a root that we will not pop off
mHead->prev = mHead;
+ mHead->type = TransformNone;
}
-void DamageAccumulator::pushNode(const RenderNode* node) {
+void DamageAccumulator::pushCommon() {
if (!mHead->next) {
DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
nextFrame->next = 0;
@@ -50,42 +68,131 @@
mHead->next = nextFrame;
}
mHead = mHead->next;
- mHead->node = node;
mHead->pendingDirty.setEmpty();
}
-void DamageAccumulator::popNode() {
+void DamageAccumulator::pushTransform(const RenderNode* transform) {
+ pushCommon();
+ mHead->type = TransformRenderNode;
+ mHead->renderNode = transform;
+}
+
+void DamageAccumulator::pushTransform(const Matrix4* transform) {
+ pushCommon();
+ mHead->type = TransformMatrix4;
+ mHead->matrix4 = transform;
+}
+
+void DamageAccumulator::pushNullTransform() {
+ pushCommon();
+ mHead->type = TransformNone;
+}
+
+void DamageAccumulator::popTransform() {
LOG_ALWAYS_FATAL_IF(mHead->prev == mHead, "Cannot pop the root frame!");
DirtyStack* dirtyFrame = mHead;
mHead = mHead->prev;
- if (!dirtyFrame->pendingDirty.isEmpty()) {
- SkRect mappedDirty;
- const RenderProperties& props = dirtyFrame->node->properties();
- const SkMatrix* transform = props.getTransformMatrix();
- if (transform && !transform->isIdentity()) {
- transform->mapRect(&mappedDirty, dirtyFrame->pendingDirty);
- } else {
- mappedDirty = dirtyFrame->pendingDirty;
+ switch (dirtyFrame->type) {
+ case TransformRenderNode:
+ applyRenderNodeTransform(dirtyFrame);
+ break;
+ case TransformMatrix4:
+ applyMatrix4Transform(dirtyFrame);
+ break;
+ case TransformNone:
+ mHead->pendingDirty.join(dirtyFrame->pendingDirty);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Tried to pop an invalid type: %d", dirtyFrame->type);
+ }
+}
+
+static inline void mapRect(const Matrix4* matrix, const SkRect& in, SkRect* out) {
+ if (in.isEmpty()) return;
+ Rect temp(in);
+ matrix->mapRect(temp);
+ out->join(RECT_ARGS(temp));
+}
+
+void DamageAccumulator::applyMatrix4Transform(DirtyStack* frame) {
+ mapRect(frame->matrix4, frame->pendingDirty, &mHead->pendingDirty);
+}
+
+static inline void mapRect(const RenderProperties& props, const SkRect& in, SkRect* out) {
+ if (in.isEmpty()) return;
+ const SkMatrix* transform = props.getTransformMatrix();
+ SkRect temp(in);
+ if (transform && !transform->isIdentity()) {
+ transform->mapRect(&temp);
+ }
+ temp.offset(props.getLeft(), props.getTop());
+ out->join(temp);
+}
+
+static DirtyStack* findParentRenderNode(DirtyStack* frame) {
+ while (frame->prev != frame) {
+ frame = frame->prev;
+ if (frame->type == TransformRenderNode) {
+ return frame;
}
- if (CC_LIKELY(mHead->node)) {
- const RenderProperties& parentProps = mHead->node->properties();
- mappedDirty.offset(props.getLeft() - parentProps.getScrollX(),
- props.getTop() - parentProps.getScrollY());
- if (props.getClipToBounds()) {
- if (!mappedDirty.intersect(0, 0, parentProps.getWidth(), parentProps.getHeight())) {
- mappedDirty.setEmpty();
- }
+ }
+ return NULL;
+}
+
+static DirtyStack* findProjectionReceiver(DirtyStack* frame) {
+ if (frame) {
+ while (frame->prev != frame) {
+ frame = frame->prev;
+ if (frame->type == TransformRenderNode
+ && frame->renderNode->hasProjectionReceiver()) {
+ return frame;
}
- if (CC_UNLIKELY(!MathUtils::isZero(props.getTranslationZ()))) {
- // TODO: Can we better bound the shadow damage area? For now
- // match the old damageShadowReceiver() path and just dirty
- // the entire parent bounds
- mappedDirty.join(0, 0, parentProps.getWidth(), parentProps.getHeight());
- }
- } else {
- mappedDirty.offset(props.getLeft(), props.getTop());
}
- dirty(mappedDirty.fLeft, mappedDirty.fTop, mappedDirty.fRight, mappedDirty.fBottom);
+ }
+ return NULL;
+}
+
+static void applyTransforms(DirtyStack* frame, DirtyStack* end) {
+ SkRect* rect = &frame->pendingDirty;
+ while (frame != end) {
+ if (frame->type == TransformRenderNode) {
+ mapRect(frame->renderNode->properties(), *rect, rect);
+ } else {
+ mapRect(frame->matrix4, *rect, rect);
+ }
+ frame = frame->prev;
+ }
+}
+
+void DamageAccumulator::applyRenderNodeTransform(DirtyStack* frame) {
+ if (frame->pendingDirty.isEmpty()) {
+ return;
+ }
+
+ const RenderProperties& props = frame->renderNode->properties();
+
+ // Perform clipping
+ if (props.getClipDamageToBounds() && !frame->pendingDirty.isEmpty()) {
+ if (!frame->pendingDirty.intersect(0, 0, props.getWidth(), props.getHeight())) {
+ frame->pendingDirty.setEmpty();
+ }
+ }
+
+ // apply all transforms
+ mapRect(props, frame->pendingDirty, &mHead->pendingDirty);
+
+ // project backwards if necessary
+ if (props.getProjectBackwards() && !frame->pendingDirty.isEmpty()) {
+ // First, find our parent RenderNode:
+ DirtyStack* parentNode = findParentRenderNode(frame);
+ // Find our parent's projection receiver, which is what we project onto
+ DirtyStack* projectionReceiver = findProjectionReceiver(parentNode);
+ if (projectionReceiver) {
+ applyTransforms(frame, projectionReceiver);
+ projectionReceiver->pendingDirty.join(frame->pendingDirty);
+ }
+
+ frame->pendingDirty.setEmpty();
}
}
@@ -93,6 +200,10 @@
mHead->pendingDirty.join(left, top, right, bottom);
}
+void DamageAccumulator::peekAtDirty(SkRect* dest) {
+ *dest = mHead->pendingDirty;
+}
+
void DamageAccumulator::finish(SkRect* totalDirty) {
LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead);
// Root node never has a transform, so this is the fully mapped dirty rect
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
index c62a351..fc9b41b 100644
--- a/libs/hwui/DamageAccumulator.h
+++ b/libs/hwui/DamageAccumulator.h
@@ -16,6 +16,7 @@
#ifndef DAMAGEACCUMULATOR_H
#define DAMAGEACCUMULATOR_H
+#include <cutils/compiler.h>
#include <utils/LinearAllocator.h>
#include <SkMatrix.h>
@@ -28,8 +29,21 @@
struct DirtyStack;
class RenderNode;
+class Matrix4;
-class DamageAccumulator {
+class IDamageAccumulator {
+public:
+ virtual void pushTransform(const RenderNode* transform) = 0;
+ virtual void pushTransform(const Matrix4* transform) = 0;
+ virtual void pushNullTransform() = 0;
+ virtual void popTransform() = 0;
+ virtual void dirty(float left, float top, float right, float bottom) = 0;
+ virtual void peekAtDirty(SkRect* dest) = 0;
+protected:
+ virtual ~IDamageAccumulator() {}
+};
+
+class DamageAccumulator : public IDamageAccumulator {
PREVENT_COPY_AND_ASSIGN(DamageAccumulator);
public:
DamageAccumulator();
@@ -37,20 +51,52 @@
// Push a transform node onto the stack. This should be called prior
// to any dirty() calls. Subsequent calls to dirty()
- // will be affected by the node's transform when popNode() is called.
- void pushNode(const RenderNode* node);
+ // will be affected by the transform when popTransform() is called.
+ virtual void pushTransform(const RenderNode* transform);
+ virtual void pushTransform(const Matrix4* transform);
+ // This is used in combination with peekAtDirty to inspect the damage
+ // area of a subtree
+ virtual void pushNullTransform();
+
// Pops a transform node from the stack, propagating the dirty rect
- // up to the parent node.
- void popNode();
- void dirty(float left, float top, float right, float bottom);
+ // up to the parent node. Returns the IDamageTransform that was just applied
+ virtual void popTransform();
+
+ virtual void dirty(float left, float top, float right, float bottom);
+
+ // Returns the current dirty area, *NOT* transformed by pushed transforms
+ virtual void peekAtDirty(SkRect* dest);
void finish(SkRect* totalDirty);
private:
+ void pushCommon();
+ void applyMatrix4Transform(DirtyStack* frame);
+ void applyRenderNodeTransform(DirtyStack* frame);
+
LinearAllocator mAllocator;
DirtyStack* mHead;
};
+class NullDamageAccumulator : public IDamageAccumulator {
+ PREVENT_COPY_AND_ASSIGN(NullDamageAccumulator);
+public:
+ virtual void pushTransform(const RenderNode* transform) { }
+ virtual void pushTransform(const Matrix4* transform) { }
+ virtual void pushNullTransform() { }
+ virtual void popTransform() { }
+ virtual void dirty(float left, float top, float right, float bottom) { }
+ virtual void peekAtDirty(SkRect* dest) { dest->setEmpty(); }
+
+ ANDROID_API static NullDamageAccumulator* instance();
+
+private:
+ NullDamageAccumulator() {}
+ ~NullDamageAccumulator() {}
+
+ static NullDamageAccumulator sInstance;
+};
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index d494c4c..8e99b9a 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -27,8 +27,7 @@
}
DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, LayerDestroyer destroyer)
- : mDisplayList(0)
- , mSurfaceTexture(0)
+ : mSurfaceTexture(0)
, mTransform(0)
, mNeedsGLContextAttach(false)
, mUpdateTexImage(false)
@@ -41,7 +40,6 @@
mColorFilter = SkSafeRef(mLayer->getColorFilter());
mAlpha = mLayer->getAlpha();
mMode = mLayer->getMode();
- mDirtyRect.setEmpty();
if (!mDestroyer) {
mDestroyer = defaultLayerDestroyer;
@@ -60,37 +58,13 @@
SkRefCnt_SafeAssign(mColorFilter, colorFilter);
}
-void DeferredLayerUpdater::setDisplayList(RenderNode* displayList,
- int left, int top, int right, int bottom) {
- mDisplayList = displayList;
- if (mDirtyRect.isEmpty()) {
- mDirtyRect.set(left, top, right, bottom);
- } else {
- mDirtyRect.unionWith(Rect(left, top, right, bottom));
- }
-}
-
bool DeferredLayerUpdater::apply(TreeInfo& info) {
bool success = true;
// These properties are applied the same to both layer types
mLayer->setColorFilter(mColorFilter);
mLayer->setAlpha(mAlpha, mMode);
- if (mDisplayList.get()) {
- if (mWidth != mLayer->layer.getWidth() || mHeight != mLayer->layer.getHeight()) {
- success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
- }
- mLayer->setBlend(mBlend);
- // TODO: Use DamageAccumulator to get the damage area for the layer's
- // subtree to only update that part of the layer. Do this as part of
- // reworking layers to be a RenderProperty instead of a View-managed object
- mDirtyRect.set(0, 0, mWidth, mHeight);
- mDisplayList->prepareTree(info);
- mLayer->updateDeferred(mDisplayList.get(),
- mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
- mDirtyRect.setEmpty();
- mDisplayList = 0;
- } else if (mSurfaceTexture.get()) {
+ if (mSurfaceTexture.get()) {
if (mNeedsGLContextAttach) {
mNeedsGLContextAttach = false;
mSurfaceTexture->attachToContext(mLayer->getTexture());
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index b7cfe80..5082271 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -74,9 +74,6 @@
mTransform = matrix ? new SkMatrix(*matrix) : 0;
}
- ANDROID_API void setDisplayList(RenderNode* displayList,
- int left, int top, int right, int bottom);
-
ANDROID_API void setPaint(const SkPaint* paint);
ANDROID_API bool apply(TreeInfo& info);
@@ -94,11 +91,6 @@
int mAlpha;
SkXfermode::Mode mMode;
- // Layer type specific properties
- // displayList and surfaceTexture are mutually exclusive, only 1 may be set
- // dirtyRect is only valid if displayList is set
- sp<RenderNode> mDisplayList;
- Rect mDirtyRect;
sp<GLConsumer> mSurfaceTexture;
SkMatrix* mTransform;
bool mNeedsGLContextAttach;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 9212b9de..233f3f0 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1114,6 +1114,15 @@
OP_LOG("Draw RoundRect " RECT_STRING ", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
}
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
+ DrawStrokableOp::onDefer(renderer, deferInfo, state);
+ if (!mPaint->getPathEffect()) {
+ renderer.getCaches().tessellationCache.precacheRoundRect(state.mMatrix,
+ mLocalBounds.getWidth(), mLocalBounds.getHeight(), mRx, mRy, mPaint);
+ }
+ }
+
virtual const char* name() { return "DrawRoundRect"; }
private:
@@ -1533,9 +1542,23 @@
}
}
+ virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
+ const DeferredDisplayState& state) {
+ renderer.getCaches().tessellationCache.precacheShadows(&state.mMatrix,
+ renderer.getLocalClipBounds(), isCasterOpaque(), &mOutline,
+ &mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius());
+ }
+
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawShadow(mTransformXY, mTransformZ,
- mCasterAlpha, mCasterUnclipped, &mOutline);
+ TessellationCache::vertexBuffer_pair_t buffers;
+ Matrix4 drawTransform;
+ renderer.getMatrix(&drawTransform);
+ renderer.getCaches().tessellationCache.getShadowBuffers(&drawTransform,
+ renderer.getLocalClipBounds(), isCasterOpaque(), &mOutline,
+ &mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius(),
+ buffers);
+
+ return renderer.drawShadow(mCasterAlpha, buffers.first, buffers.second);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -1545,6 +1568,8 @@
virtual const char* name() { return "DrawShadow"; }
private:
+ bool isCasterOpaque() { return mCasterAlpha >= 1.0f && mCasterUnclipped; }
+
const mat4 mTransformXY;
const mat4 mTransformZ;
const float mCasterAlpha;
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 6a2ef2a..1002e13 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -185,6 +185,7 @@
}
void Layer::clearTexture() {
+ caches.unbindTexture(texture.id);
texture.id = 0;
}
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index df9aee5..a5fd375 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -334,8 +334,10 @@
void LayerRenderer::flushLayer(Layer* layer) {
#ifdef GL_EXT_discard_framebuffer
+ if (!layer) return;
+
GLuint fbo = layer->getFbo();
- if (layer && fbo) {
+ if (fbo) {
// If possible, discard any enqueud operations on deferred
// rendering architectures
if (Extensions::getInstance().hasDiscardFramebuffer()) {
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 2268386..9f2014f 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -417,6 +417,8 @@
}
void Matrix4::mapRect(Rect& r) const {
+ if (isIdentity()) return;
+
if (isSimple()) {
MUL_ADD_STORE(r.left, data[kScaleX], data[kTranslateX]);
MUL_ADD_STORE(r.right, data[kScaleX], data[kTranslateX]);
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index e33a001..1c5c578 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -147,6 +147,7 @@
data[kTranslateX] += x;
data[kTranslateY] += y;
data[kTranslateZ] += z;
+ mType |= kTypeUnknown;
} else {
// Doing a translation will only affect the translate bit of the type
// Save the type
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index cd09f86..8f3872a 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -287,6 +287,7 @@
// of the current frame
if (getTargetFbo() == 0) {
mCaches.pathCache.trim();
+ mCaches.tessellationCache.trim();
}
if (!suppressErrorChecks()) {
@@ -2390,7 +2391,7 @@
return DrawGlInfo::kStatusDrew;
}
-status_t OpenGLRenderer::drawVertexBuffer(VertexBufferMode mode,
+status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
const VertexBuffer& vertexBuffer, const SkPaint* paint, bool useOffset) {
// not missing call to quickReject/dirtyLayer, always done at a higher level
if (!vertexBuffer.getVertexCount()) {
@@ -2398,6 +2399,9 @@
return DrawGlInfo::kStatusDone;
}
+ const Rect& bounds = vertexBuffer.getBounds();
+ dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
+
int color = paint->getColor();
bool isAA = paint->isAntiAlias();
@@ -2409,7 +2413,7 @@
setupDrawShader(getShader(paint));
setupDrawBlending(paint, isAA);
setupDrawProgram();
- setupDrawModelView(kModelViewMode_Translate, useOffset, 0, 0, 0, 0);
+ setupDrawModelView(kModelViewMode_Translate, useOffset, translateX, translateY, 0, 0);
setupDrawColorUniforms(getShader(paint));
setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawShaderUniforms(getShader(paint));
@@ -2429,13 +2433,14 @@
glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
}
- if (mode == kVertexBufferMode_Standard) {
+ const VertexBuffer::Mode mode = vertexBuffer.getMode();
+ if (mode == VertexBuffer::kStandard) {
mCaches.unbindIndicesBuffer();
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
- } else if (mode == kVertexBufferMode_OnePolyRingShadow) {
+ } else if (mode == VertexBuffer::kOnePolyRingShadow) {
mCaches.bindShadowIndicesBuffer();
glDrawElements(GL_TRIANGLE_STRIP, ONE_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
- } else if (mode == kVertexBufferMode_TwoPolyRingShadow) {
+ } else if (mode == VertexBuffer::kTwoPolyRingShadow) {
mCaches.bindShadowIndicesBuffer();
glDrawElements(GL_TRIANGLE_STRIP, TWO_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
}
@@ -2460,14 +2465,7 @@
VertexBuffer vertexBuffer;
// TODO: try clipping large paths to viewport
PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer);
-
- if (hasLayer()) {
- SkRect bounds = path.getBounds();
- PathTessellator::expandBoundsForStroke(bounds, paint);
- dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *currentTransform());
- }
-
- return drawVertexBuffer(kVertexBufferMode_Standard, vertexBuffer, paint);
+ return drawVertexBuffer(vertexBuffer, paint);
}
/**
@@ -2487,18 +2485,15 @@
count &= ~0x3; // round down to nearest four
VertexBuffer buffer;
- SkRect bounds;
- PathTessellator::tessellateLines(points, count, paint, *currentTransform(), bounds, buffer);
+ PathTessellator::tessellateLines(points, count, paint, *currentTransform(), buffer);
+ const Rect& bounds = buffer.getBounds();
- // can't pass paint, since style would be checked for outset. outset done by tessellation.
- if (quickRejectSetupScissor(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom)) {
+ if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
return DrawGlInfo::kStatusDone;
}
- dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *currentTransform());
-
bool useOffset = !paint->isAntiAlias();
- return drawVertexBuffer(kVertexBufferMode_Standard, buffer, paint, useOffset);
+ return drawVertexBuffer(buffer, paint, useOffset);
}
status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
@@ -2507,18 +2502,15 @@
count &= ~0x1; // round down to nearest two
VertexBuffer buffer;
- SkRect bounds;
- PathTessellator::tessellatePoints(points, count, paint, *currentTransform(), bounds, buffer);
+ PathTessellator::tessellatePoints(points, count, paint, *currentTransform(), buffer);
- // can't pass paint, since style would be checked for outset. outset done by tessellation.
- if (quickRejectSetupScissor(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom)) {
+ const Rect& bounds = buffer.getBounds();
+ if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
return DrawGlInfo::kStatusDone;
}
- dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, *currentTransform());
-
bool useOffset = !paint->isAntiAlias();
- return drawVertexBuffer(kVertexBufferMode_Standard, buffer, paint, useOffset);
+ return drawVertexBuffer(buffer, paint, useOffset);
}
status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
@@ -2564,16 +2556,9 @@
return drawShape(left, top, texture, p);
}
- SkPath path;
- SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
- if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
- float outset = p->getStrokeWidth() / 2;
- rect.outset(outset, outset);
- rx += outset;
- ry += outset;
- }
- path.addRoundRect(rect, rx, ry);
- return drawConvexPath(path, p);
+ const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(*currentTransform(),
+ right - left, bottom - top, rx, ry, p);
+ return drawVertexBuffer(left, top, *vertexBuffer, p);
}
status_t OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
@@ -3192,8 +3177,8 @@
transformXY.mapPoint(point.x, point.y);
}
-status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ,
- float casterAlpha, bool casterUnclipped, const SkPath* casterPerimeter) {
+status_t OpenGLRenderer::drawShadow(float casterAlpha,
+ const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
// TODO: use quickRejectWithScissor. For now, always force enable scissor.
@@ -3202,77 +3187,14 @@
SkPaint paint;
paint.setAntiAlias(true); // want to use AlphaVertex
- // tessellate caster outline into a 2d polygon
- Vector<Vertex> casterVertices2d;
- const float casterRefinementThresholdSquared = 20.0f; // TODO: experiment with this value
- PathTessellator::approximatePathOutlineVertices(*casterPerimeter,
- casterRefinementThresholdSquared, casterVertices2d);
- if (!ShadowTessellator::isClockwisePath(*casterPerimeter)) {
- ShadowTessellator::reverseVertexArray(casterVertices2d.editArray(),
- casterVertices2d.size());
- }
-
- if (casterVertices2d.size() == 0) {
- // empty caster polygon computed from path
- return DrawGlInfo::kStatusDone;
- }
-
- // map 2d caster poly into 3d
- const int casterVertexCount = casterVertices2d.size();
- Vector3 casterPolygon[casterVertexCount];
- float minZ = FLT_MAX;
- float maxZ = -FLT_MAX;
- for (int i = 0; i < casterVertexCount; i++) {
- const Vertex& point2d = casterVertices2d[i];
- casterPolygon[i] = Vector3(point2d.x, point2d.y, 0);
- mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ);
- minZ = fmin(minZ, casterPolygon[i].z);
- maxZ = fmax(maxZ, casterPolygon[i].z);
- }
-
- // map the centroid of the caster into 3d
- Vector2 centroid = ShadowTessellator::centroid2d(
- reinterpret_cast<const Vector2*>(casterVertices2d.array()),
- casterVertexCount);
- Vector3 centroid3d(centroid.x, centroid.y, 0);
- mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ);
-
- // if the caster intersects the z=0 plane, lift it in Z so it doesn't
- if (minZ < SHADOW_MIN_CASTER_Z) {
- float casterLift = SHADOW_MIN_CASTER_Z - minZ;
- for (int i = 0; i < casterVertexCount; i++) {
- casterPolygon[i].z += casterLift;
- }
- centroid3d.z += casterLift;
- }
-
- // Check whether we want to draw the shadow at all by checking the caster's
- // bounds against clip.
- // We only have ortho projection, so we can just ignore the Z in caster for
- // simple rejection calculation.
- Rect localClip = mSnapshot->getLocalClip();
- Rect casterBounds(casterPerimeter->getBounds());
- casterTransformXY.mapRect(casterBounds);
-
- bool isCasterOpaque = (casterAlpha == 1.0f) && casterUnclipped;
- // draw caster's shadows
- if (mCaches.propertyAmbientShadowStrength > 0) {
+ if (ambientShadowVertexBuffer && mCaches.propertyAmbientShadowStrength > 0) {
paint.setARGB(casterAlpha * mCaches.propertyAmbientShadowStrength, 0, 0, 0);
- VertexBuffer ambientShadowVertexBuffer;
- VertexBufferMode vertexBufferMode = ShadowTessellator::tessellateAmbientShadow(
- isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
- casterBounds, localClip, maxZ, ambientShadowVertexBuffer);
- drawVertexBuffer(vertexBufferMode, ambientShadowVertexBuffer, &paint);
+ drawVertexBuffer(*ambientShadowVertexBuffer, &paint);
}
- if (mCaches.propertySpotShadowStrength > 0) {
+ if (spotShadowVertexBuffer && mCaches.propertySpotShadowStrength > 0) {
paint.setARGB(casterAlpha * mCaches.propertySpotShadowStrength, 0, 0, 0);
- VertexBuffer spotShadowVertexBuffer;
- VertexBufferMode vertexBufferMode = ShadowTessellator::tessellateSpotShadow(
- isCasterOpaque, casterPolygon, casterVertexCount,
- *currentTransform(), mLightCenter, mLightRadius, casterBounds, localClip,
- spotShadowVertexBuffer);
- drawVertexBuffer(vertexBufferMode, spotShadowVertexBuffer, &paint);
+ drawVertexBuffer(*spotShadowVertexBuffer, &paint);
}
return DrawGlInfo::kStatusDrew;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 0f953a5..346a65c 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -111,12 +111,6 @@
kModelViewMode_TranslateAndScale = 1,
};
-enum VertexBufferMode {
- kVertexBufferMode_Standard = 0,
- kVertexBufferMode_OnePolyRingShadow = 1,
- kVertexBufferMode_TwoPolyRingShadow = 2
-};
-
///////////////////////////////////////////////////////////////////////////////
// Renderer
///////////////////////////////////////////////////////////////////////////////
@@ -213,8 +207,8 @@
DrawOpMode drawOpMode = kDrawOpMode_Immediate);
virtual status_t drawRects(const float* rects, int count, const SkPaint* paint);
- status_t drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ,
- float casterAlpha, bool casterUnclipped, const SkPath* casterPerimeter);
+ status_t drawShadow(float casterAlpha,
+ const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer);
virtual void resetPaintFilter();
virtual void setupPaintFilter(int clearBits, int setBits);
@@ -348,6 +342,9 @@
}
#endif
+ const Vector3& getLightCenter() const { return mLightCenter; }
+ float getLightRadius() const { return mLightRadius; }
+
protected:
/**
* Perform the setup specific to a frame. This method does not
@@ -661,10 +658,18 @@
* @param paint The paint to render with
* @param useOffset Offset the vertexBuffer (used in drawing non-AA lines)
*/
- status_t drawVertexBuffer(VertexBufferMode mode, const VertexBuffer& vertexBuffer,
+ status_t drawVertexBuffer(float translateX, float translateY, const VertexBuffer& vertexBuffer,
const SkPaint* paint, bool useOffset = false);
/**
+ * Convenience for translating method
+ */
+ status_t drawVertexBuffer(const VertexBuffer& vertexBuffer,
+ const SkPaint* paint, bool useOffset = false) {
+ return drawVertexBuffer(0.0f, 0.0f, vertexBuffer, paint, useOffset);
+ }
+
+ /**
* Renders the convex hull defined by the specified path as a strip of polygons.
*
* @param path The hull of the path to draw
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index d9c06d3..9dd5aa5 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -74,10 +74,6 @@
return JenkinsHashWhiten(hash);
}
-int PathDescription::compare(const PathDescription& rhs) const {
- return memcmp(this, &rhs, sizeof(PathDescription));
-}
-
///////////////////////////////////////////////////////////////////////////////
// Utilities
///////////////////////////////////////////////////////////////////////////////
@@ -163,14 +159,7 @@
} else {
INIT_LOGD(" Using default %s cache size of %.2fMB", name, DEFAULT_PATH_CACHE_SIZE);
}
- init();
-}
-PathCache::~PathCache() {
- mCache.clear();
-}
-
-void PathCache::init() {
mCache.setOnEntryRemovedListener(this);
GLint maxTextureSize;
@@ -180,6 +169,10 @@
mDebugEnabled = readDebugLevel() & kDebugCaches;
}
+PathCache::~PathCache() {
+ mCache.clear();
+}
+
///////////////////////////////////////////////////////////////////////////////
// Size management
///////////////////////////////////////////////////////////////////////////////
@@ -341,7 +334,7 @@
}
void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
- sp<PathTask> t = static_cast<PathTask* >(task.get());
+ PathTask* t = static_cast<PathTask*>(task.get());
ATRACE_NAME("pathPrecache");
float left, top, offset;
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index bcfb367..eee138b 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -26,6 +26,7 @@
#include "Debug.h"
#include "Properties.h"
#include "Texture.h"
+#include "utils/Macros.h"
#include "utils/Pair.h"
class SkBitmap;
@@ -107,6 +108,7 @@
};
struct PathDescription {
+ DESCRIPTION_TYPE(PathDescription);
ShapeType type;
SkPaint::Join join;
SkPaint::Cap cap;
@@ -148,29 +150,6 @@
PathDescription(ShapeType shapeType, const SkPaint* paint);
hash_t hash() const;
-
- int compare(const PathDescription& rhs) const;
-
- bool operator==(const PathDescription& other) const {
- return compare(other) == 0;
- }
-
- bool operator!=(const PathDescription& other) const {
- return compare(other) != 0;
- }
-
- friend inline int strictly_order_type(
- const PathDescription& lhs, const PathDescription& rhs) {
- return lhs.compare(rhs) < 0;
- }
-
- friend inline int compare_type(const PathDescription& lhs, const PathDescription& rhs) {
- return lhs.compare(rhs);
- }
-
- friend inline hash_t hash_type(const PathDescription& entry) {
- return entry.hash();
- }
};
/**
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 4ef2158..310b107 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -57,15 +57,26 @@
#define ROUND_CAP_THRESH 0.25f
#define PI 3.1415926535897932f
-/**
- * Note: this function doesn't account for the AA case with sub-pixel line thickness (not just 0 <
- * width < 1.0, canvas scale factors in as well) so this can't be used for points/lines
- */
-void PathTessellator::expandBoundsForStroke(SkRect& bounds, const SkPaint* paint) {
- if (paint->getStyle() != SkPaint::kFill_Style) {
- float outset = paint->getStrokeWidth() * 0.5f;
- if (outset == 0) outset = 0.5f; // account for hairline
- bounds.outset(outset, outset);
+// temporary error thresholds
+#define ERROR_DEPTH 20
+#define ERROR_SCALE 1e10
+#define ERROR_SQR_INV_THRESH 1e-20
+
+void PathTessellator::extractTessellationScales(const Matrix4& transform,
+ float* scaleX, float* scaleY) {
+ if (CC_LIKELY(transform.isPureTranslate())) {
+ *scaleX = 1.0f;
+ *scaleY = 1.0f;
+ } else {
+ float m00 = transform.data[Matrix4::kScaleX];
+ float m01 = transform.data[Matrix4::kSkewY];
+ float m10 = transform.data[Matrix4::kSkewX];
+ float m11 = transform.data[Matrix4::kScaleY];
+ *scaleX = sqrt(m00 * m00 + m01 * m01);
+ *scaleY = sqrt(m10 * m10 + m11 * m11);
+
+ LOG_ALWAYS_FATAL_IF(*scaleX > ERROR_SCALE || *scaleY > ERROR_SCALE,
+ "scales %e x %e too large for tessellation", *scaleX, *scaleY);
}
}
@@ -90,22 +101,21 @@
public:
PaintInfo(const SkPaint* paint, const mat4& transform) :
style(paint->getStyle()), cap(paint->getStrokeCap()), isAA(paint->isAntiAlias()),
- inverseScaleX(1.0f), inverseScaleY(1.0f),
halfStrokeWidth(paint->getStrokeWidth() * 0.5f), maxAlpha(1.0f) {
// compute inverse scales
- if (CC_UNLIKELY(!transform.isPureTranslate())) {
- float m00 = transform.data[Matrix4::kScaleX];
- float m01 = transform.data[Matrix4::kSkewY];
- float m10 = transform.data[Matrix4::kSkewX];
- float m11 = transform.data[Matrix4::kScaleY];
- float scaleX = sqrt(m00 * m00 + m01 * m01);
- float scaleY = sqrt(m10 * m10 + m11 * m11);
+ if (CC_LIKELY(transform.isPureTranslate())) {
+ inverseScaleX = 1.0f;
+ inverseScaleY = 1.0f;
+ } else {
+ float scaleX, scaleY;
+ PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY);
inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 1.0f;
inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 1.0f;
}
if (isAA && halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
2 * halfStrokeWidth < inverseScaleX) {
+ // AA, with non-hairline stroke, width < 1 pixel. Scale alpha and treat as hairline.
maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
halfStrokeWidth = 0.0f;
}
@@ -159,10 +169,10 @@
* Outset the bounds of point data (for line endpoints or points) to account for AA stroke
* geometry.
*/
- void expandBoundsForStrokeAA(SkRect& bounds) const {
+ void expandBoundsForStroke(Rect* bounds) const {
float outset = halfStrokeWidth;
if (outset == 0) outset = 0.5f;
- bounds.outset(outset * inverseScaleX + Vertex::GeometryFudgeFactor(),
+ bounds->outset(outset * inverseScaleX + Vertex::GeometryFudgeFactor(),
outset * inverseScaleY + Vertex::GeometryFudgeFactor());
}
};
@@ -778,21 +788,25 @@
getFillVerticesFromPerimeterAA(paintInfo, tempVertices, vertexBuffer);
}
}
+
+ Rect bounds(path.getBounds());
+ paintInfo.expandBoundsForStroke(&bounds);
+ vertexBuffer.setBounds(bounds);
}
-static void expandRectToCoverVertex(SkRect& rect, float x, float y) {
- rect.fLeft = fminf(rect.fLeft, x);
- rect.fTop = fminf(rect.fTop, y);
- rect.fRight = fmaxf(rect.fRight, x);
- rect.fBottom = fmaxf(rect.fBottom, y);
+static void expandRectToCoverVertex(Rect& rect, float x, float y) {
+ rect.left = fminf(rect.left, x);
+ rect.top = fminf(rect.top, y);
+ rect.right = fmaxf(rect.right, x);
+ rect.bottom = fmaxf(rect.bottom, y);
}
-static void expandRectToCoverVertex(SkRect& rect, const Vertex& vertex) {
+static void expandRectToCoverVertex(Rect& rect, const Vertex& vertex) {
expandRectToCoverVertex(rect, vertex.x, vertex.y);
}
template <class TYPE>
static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer,
- const float* points, int count, SkRect& bounds) {
+ const float* points, int count, Rect& bounds) {
bounds.set(points[0], points[1], points[0], points[1]);
int numPoints = count / 2;
@@ -807,7 +821,7 @@
}
void PathTessellator::tessellatePoints(const float* points, int count, const SkPaint* paint,
- const mat4& transform, SkRect& bounds, VertexBuffer& vertexBuffer) {
+ const mat4& transform, VertexBuffer& vertexBuffer) {
const PaintInfo paintInfo(paint, transform);
// determine point shape
@@ -830,6 +844,7 @@
if (!outlineVertices.size()) return;
+ Rect bounds;
// tessellate, then duplicate outline across points
int numPoints = count / 2;
VertexBuffer tempBuffer;
@@ -843,12 +858,12 @@
}
// expand bounds from vertex coords to pixel data
- paintInfo.expandBoundsForStrokeAA(bounds);
-
+ paintInfo.expandBoundsForStroke(&bounds);
+ vertexBuffer.setBounds(bounds);
}
void PathTessellator::tessellateLines(const float* points, int count, const SkPaint* paint,
- const mat4& transform, SkRect& bounds, VertexBuffer& vertexBuffer) {
+ const mat4& transform, VertexBuffer& vertexBuffer) {
ATRACE_CALL();
const PaintInfo paintInfo(paint, transform);
@@ -868,6 +883,7 @@
tempVertices.push();
tempVertices.push();
Vertex* tempVerticesData = tempVertices.editArray();
+ Rect bounds;
bounds.set(points[0], points[1], points[0], points[1]);
for (int i = 0; i < count; i += 4) {
Vertex::set(&(tempVerticesData[0]), points[i + 0], points[i + 1]);
@@ -892,7 +908,8 @@
}
// expand bounds from vertex coords to pixel data
- paintInfo.expandBoundsForStrokeAA(bounds);
+ paintInfo.expandBoundsForStroke(&bounds);
+ vertexBuffer.setBounds(bounds);
}
///////////////////////////////////////////////////////////////////////////////
@@ -916,6 +933,9 @@
Vector<Vertex>& outputVertices) {
ATRACE_CALL();
+ LOG_ALWAYS_FATAL_IF(sqrInvScaleX < ERROR_SQR_INV_THRESH || sqrInvScaleY < ERROR_SQR_INV_THRESH,
+ "Invalid scale factors used for approx %e, %e", sqrInvScaleX, sqrInvScaleY);
+
// TODO: to support joins other than sharp miter, join vertices should be labelled in the
// perimeter, or resolved into more vertices. Reconsider forceClose-ing in that case.
SkPath::Iter iter(path, forceClose);
@@ -973,7 +993,10 @@
float p1x, float p1y, float c1x, float c1y,
float p2x, float p2y, float c2x, float c2y,
float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
- Vector<Vertex>& outputVertices) {
+ Vector<Vertex>& outputVertices, int depth) {
+ LOG_ALWAYS_FATAL_IF(depth >= ERROR_DEPTH, "ERROR DEPTH exceeded: cubic approx, invscale %e x %e, vertcount %d",
+ sqrInvScaleX, sqrInvScaleY, outputVertices.size());
+
float dx = p2x - p1x;
float dy = p2y - p1y;
float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx);
@@ -981,7 +1004,6 @@
float d = d1 + d2;
// multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
-
if (d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
// below thresh, draw line by adding endpoint
pushToVector(outputVertices, p2x, p2y);
@@ -1006,11 +1028,11 @@
recursiveCubicBezierVertices(
p1x, p1y, p1c1x, p1c1y,
mx, my, p1c1c2x, p1c1c2y,
- sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
+ sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
recursiveCubicBezierVertices(
mx, my, p2c1c2x, p2c1c2y,
p2x, p2y, p2c2x, p2c2y,
- sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
+ sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
}
}
@@ -1019,7 +1041,10 @@
float bx, float by,
float cx, float cy,
float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
- Vector<Vertex>& outputVertices) {
+ Vector<Vertex>& outputVertices, int depth) {
+ LOG_ALWAYS_FATAL_IF(depth >= ERROR_DEPTH, "ERROR_DEPTH exceeded: quadratic approx, invscale %e x %e, vertcount %d",
+ sqrInvScaleX, sqrInvScaleY, outputVertices.size());
+
float dx = bx - ax;
float dy = by - ay;
float d = (cx - bx) * dy - (cy - by) * dx;
@@ -1038,9 +1063,9 @@
float my = (acy + bcy) * 0.5f;
recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy,
- sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
+ sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy,
- sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
+ sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
}
}
diff --git a/libs/hwui/PathTessellator.h b/libs/hwui/PathTessellator.h
index a215b7a..8ac9a3b 100644
--- a/libs/hwui/PathTessellator.h
+++ b/libs/hwui/PathTessellator.h
@@ -29,7 +29,15 @@
class PathTessellator {
public:
- static void expandBoundsForStroke(SkRect& bounds, const SkPaint* paint);
+ /**
+ * Populates scaleX and scaleY with the 'tessellation scale' of the transform - the effective X
+ * and Y scales that tessellation will take into account when generating the 1.0 pixel thick
+ * ramp.
+ *
+ * Two instances of the same shape (size, paint, etc.) will only generate the same vertices if
+ * their tessellation scales are equal.
+ */
+ static void extractTessellationScales(const Matrix4& transform, float* scaleX, float* scaleY);
/**
* Populates a VertexBuffer with a tessellated approximation of the input convex path, as a single
@@ -54,11 +62,10 @@
* @param paint The paint the points will be drawn with indicating AA, stroke width & cap
* @param transform The transform the points will be drawn with, used to drive stretch-aware path
* vertex approximation, and correct AA ramp offsetting
- * @param bounds An output rectangle, which returns the total area covered by the output buffer
* @param vertexBuffer The output buffer
*/
static void tessellatePoints(const float* points, int count, const SkPaint* paint,
- const mat4& transform, SkRect& bounds, VertexBuffer& vertexBuffer);
+ const mat4& transform, VertexBuffer& vertexBuffer);
/**
* Populates a VertexBuffer with a tessellated approximation of lines as a single triangle
@@ -69,11 +76,10 @@
* @param paint The paint the lines will be drawn with indicating AA, stroke width & cap
* @param transform The transform the points will be drawn with, used to drive stretch-aware path
* vertex approximation, and correct AA ramp offsetting
- * @param bounds An output rectangle, which returns the total area covered by the output buffer
* @param vertexBuffer The output buffer
*/
static void tessellateLines(const float* points, int count, const SkPaint* paint,
- const mat4& transform, SkRect& bounds, VertexBuffer& vertexBuffer);
+ const mat4& transform, VertexBuffer& vertexBuffer);
/**
* Approximates a convex, CW outline into a Vector of 2d vertices.
@@ -99,7 +105,7 @@
float bx, float by,
float cx, float cy,
float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
- Vector<Vertex> &outputVertices);
+ Vector<Vertex> &outputVertices, int depth = 0);
/*
endpoints p1, p2
@@ -111,7 +117,7 @@
float p2x, float p2y,
float c2x, float c2y,
float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
- Vector<Vertex> &outputVertices);
+ Vector<Vertex> &outputVertices, int depth = 0);
};
}; // namespace uirenderer
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 12241b8..feaee8e 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -176,6 +176,7 @@
#define PROPERTY_RENDER_BUFFER_CACHE_SIZE "ro.hwui.r_buffer_cache_size"
#define PROPERTY_GRADIENT_CACHE_SIZE "ro.hwui.gradient_cache_size"
#define PROPERTY_PATH_CACHE_SIZE "ro.hwui.path_cache_size"
+#define PROPERTY_VERTEX_CACHE_SIZE "ro.hwui.vertex_cache_size"
#define PROPERTY_PATCH_CACHE_SIZE "ro.hwui.patch_cache_size"
#define PROPERTY_DROP_SHADOW_CACHE_SIZE "ro.hwui.drop_shadow_cache_size"
#define PROPERTY_FBO_CACHE_SIZE "ro.hwui.fbo_cache_size"
@@ -222,6 +223,7 @@
#define DEFAULT_LAYER_CACHE_SIZE 16.0f
#define DEFAULT_RENDER_BUFFER_CACHE_SIZE 2.0f
#define DEFAULT_PATH_CACHE_SIZE 10.0f
+#define DEFAULT_VERTEX_CACHE_SIZE 1.0f
#define DEFAULT_PATCH_CACHE_SIZE 128 // in kB
#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 2ddbbd7..846ebdc 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -186,6 +186,13 @@
bottom += delta;
}
+ void outset(float xdelta, float ydelta) {
+ left -= xdelta;
+ top -= ydelta;
+ right += xdelta;
+ bottom += ydelta;
+ }
+
/**
* Similar to snapToPixelBoundaries, but estimates bounds conservatively to handle GL rounding
* errors.
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index c2f6df8..fc51170 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -15,6 +15,7 @@
*/
#define ATRACE_TAG ATRACE_TAG_VIEW
+#define LOG_TAG "RenderNode"
#include "RenderNode.h"
@@ -29,6 +30,8 @@
#include "Debug.h"
#include "DisplayListOp.h"
#include "DisplayListLogBuffer.h"
+#include "LayerRenderer.h"
+#include "OpenGLRenderer.h"
#include "utils/MathUtils.h"
namespace android {
@@ -58,12 +61,14 @@
, mNeedsDisplayListDataSync(false)
, mDisplayListData(0)
, mStagingDisplayListData(0)
- , mNeedsAnimatorsSync(false) {
+ , mNeedsAnimatorsSync(false)
+ , mLayer(0) {
}
RenderNode::~RenderNode() {
delete mDisplayListData;
delete mStagingDisplayListData;
+ LayerRenderer::destroyLayerDeferred(mLayer);
}
void RenderNode::setStagingDisplayList(DisplayListData* data) {
@@ -111,36 +116,85 @@
prepareTreeImpl(info);
}
-static inline void pushNode(RenderNode* self, TreeInfo& info) {
- if (info.damageAccumulator) {
- info.damageAccumulator->pushNode(self);
- }
-}
-
-static inline void popNode(TreeInfo& info) {
- if (info.damageAccumulator) {
- info.damageAccumulator->popNode();
- }
-}
-
void RenderNode::damageSelf(TreeInfo& info) {
- if (info.damageAccumulator && isRenderable() && properties().getAlpha() > 0) {
- info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight());
+ if (isRenderable() && properties().getAlpha() > 0) {
+ if (properties().getClipDamageToBounds()) {
+ info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight());
+ } else {
+ // Hope this is big enough?
+ // TODO: Get this from the display list ops or something
+ info.damageAccumulator->dirty(INT_MIN, INT_MIN, INT_MAX, INT_MAX);
+ }
+ }
+}
+
+void RenderNode::prepareLayer(TreeInfo& info) {
+ LayerType layerType = properties().layerProperties().type();
+ if (CC_UNLIKELY(layerType == kLayerTypeRenderLayer)) {
+ // We push a null transform here as we don't care what the existing dirty
+ // area is, only what our display list dirty is as well as our children's
+ // dirty area
+ info.damageAccumulator->pushNullTransform();
+ }
+}
+
+void RenderNode::pushLayerUpdate(TreeInfo& info) {
+ LayerType layerType = properties().layerProperties().type();
+ // If we are not a layer OR we cannot be rendered (eg, view was detached)
+ // we need to destroy any Layers we may have had previously
+ if (CC_LIKELY(layerType != kLayerTypeRenderLayer) || CC_UNLIKELY(!isRenderable())) {
+ if (layerType == kLayerTypeRenderLayer) {
+ info.damageAccumulator->popTransform();
+ }
+ if (CC_UNLIKELY(mLayer)) {
+ LayerRenderer::destroyLayer(mLayer);
+ mLayer = NULL;
+ }
+ return;
+ }
+
+ if (!mLayer) {
+ mLayer = LayerRenderer::createRenderLayer(getWidth(), getHeight());
+ applyLayerPropertiesToLayer(info);
+ damageSelf(info);
+ } else if (mLayer->layer.getWidth() != getWidth() || mLayer->layer.getHeight() != getHeight()) {
+ LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight());
+ damageSelf(info);
+ }
+
+ SkRect dirty;
+ info.damageAccumulator->peekAtDirty(&dirty);
+ info.damageAccumulator->popTransform();
+
+ if (!dirty.isEmpty()) {
+ mLayer->updateDeferred(this, dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom);
+ }
+ // This is not inside the above if because we may have called
+ // updateDeferred on a previous prepare pass that didn't have a renderer
+ if (info.renderer && mLayer->deferredUpdateScheduled) {
+ info.renderer->pushLayerUpdate(mLayer);
}
}
void RenderNode::prepareTreeImpl(TreeInfo& info) {
- pushNode(this, info);
+ info.damageAccumulator->pushTransform(this);
if (info.mode == TreeInfo::MODE_FULL) {
- pushStagingChanges(info);
+ pushStagingPropertiesChanges(info);
evaluateAnimations(info);
} else if (info.mode == TreeInfo::MODE_MAYBE_DETACHING) {
- pushStagingChanges(info);
+ pushStagingPropertiesChanges(info);
} else if (info.mode == TreeInfo::MODE_RT_ONLY) {
evaluateAnimations(info);
}
+
+ prepareLayer(info);
+ if (info.mode == TreeInfo::MODE_FULL) {
+ pushStagingDisplayListChanges(info);
+ }
prepareSubTree(info, mDisplayListData);
- popNode(info);
+ pushLayerUpdate(info);
+
+ info.damageAccumulator->popTransform();
}
class PushAnimatorsFunctor {
@@ -157,7 +211,7 @@
TreeInfo& mInfo;
};
-void RenderNode::pushStagingChanges(TreeInfo& info) {
+void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
// Push the animators first so that setupStartValueIfNecessary() is called
// before properties() is trampled by stagingProperties(), as they are
// required by some animators.
@@ -173,16 +227,29 @@
if (mDirtyPropertyFields) {
mDirtyPropertyFields = 0;
damageSelf(info);
- popNode(info);
+ info.damageAccumulator->popTransform();
mProperties = mStagingProperties;
- pushNode(this, info);
+ applyLayerPropertiesToLayer(info);
// We could try to be clever and only re-damage if the matrix changed.
// However, we don't need to worry about that. The cost of over-damaging
// here is only going to be a single additional map rect of this node
// plus a rect join(). The parent's transform (and up) will only be
// performed once.
+ info.damageAccumulator->pushTransform(this);
damageSelf(info);
}
+}
+
+void RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) {
+ if (CC_LIKELY(!mLayer)) return;
+
+ const LayerProperties& props = properties().layerProperties();
+ mLayer->setAlpha(props.alpha(), props.xferMode());
+ mLayer->setColorFilter(props.colorFilter());
+ mLayer->setBlend(props.needsBlending());
+}
+
+void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
if (mNeedsDisplayListDataSync) {
mNeedsDisplayListDataSync = false;
// Do a push pass on the old tree to handle freeing DisplayListData
@@ -217,7 +284,7 @@
// property push and just damage self before and after animators are run
damageSelf(info);
- popNode(info);
+ info.damageAccumulator->popTransform();
AnimateFunctor functor(this, info);
std::vector< sp<BaseRenderNodeAnimator> >::iterator newEnd;
@@ -226,7 +293,7 @@
mProperties.updateMatrix();
info.out.hasAnimations |= mAnimators.size();
- pushNode(this, info);
+ info.damageAccumulator->pushTransform(this);
damageSelf(info);
}
@@ -243,8 +310,11 @@
info.prepareTextures = cache.prefetchAndMarkInUse(subtree->bitmapResources[i]);
}
for (size_t i = 0; i < subtree->children().size(); i++) {
- RenderNode* childNode = subtree->children()[i]->mDisplayList;
+ DrawDisplayListOp* op = subtree->children()[i];
+ RenderNode* childNode = op->mDisplayList;
+ info.damageAccumulator->pushTransform(&op->mTransformFromParent);
childNode->prepareTreeImpl(info);
+ info.damageAccumulator->popTransform();
}
}
}
@@ -276,9 +346,10 @@
renderer.concatMatrix(*properties().getTransformMatrix());
}
}
- bool clipToBoundsNeeded = properties().getCaching() ? false : properties().getClipToBounds();
+ const bool isLayer = properties().layerProperties().type() != kLayerTypeNone;
+ bool clipToBoundsNeeded = isLayer ? false : properties().getClipToBounds();
if (properties().getAlpha() < 1) {
- if (properties().getCaching()) {
+ if (isLayer) {
renderer.setOverrideLayerAlpha(properties().getAlpha());
} else if (!properties().getHasOverlappingRendering()) {
renderer.scaleAlpha(properties().getAlpha());
@@ -693,8 +764,14 @@
*/
template <class T>
void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
+ const bool drawLayer = (mLayer && (&renderer != mLayer->renderer));
+ // If we are updating the contents of mLayer, we don't want to apply any of
+ // the RenderNode's properties to this issueOperations pass. Those will all
+ // be applied when the layer is drawn, aka when this is true.
+ const bool useViewProperties = (!mLayer || drawLayer);
+
const int level = handler.level();
- if (mDisplayListData->isEmpty() || properties().getAlpha() <= 0) {
+ if (mDisplayListData->isEmpty() || (useViewProperties && properties().getAlpha() <= 0)) {
DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName());
return;
}
@@ -716,7 +793,9 @@
DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
- setViewProperties<T>(renderer, handler);
+ if (useViewProperties) {
+ setViewProperties<T>(renderer, handler);
+ }
bool quickRejected = properties().getClipToBounds()
&& renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
@@ -725,31 +804,36 @@
renderer.setClippingOutline(alloc, &(mProperties.getOutline()));
}
- Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
- buildZSortedChildList(zTranslatedNodes);
+ if (drawLayer) {
+ handler(new (alloc) DrawLayerOp(mLayer, 0, 0),
+ renderer.getSaveCount() - 1, properties().getClipToBounds());
+ } else {
+ Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
+ buildZSortedChildList(zTranslatedNodes);
- // for 3d root, draw children with negative z values
- issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
+ // for 3d root, draw children with negative z values
+ issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
- DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
- const int saveCountOffset = renderer.getSaveCount() - 1;
- const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
- for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
- DisplayListOp *op = mDisplayListData->displayListOps[i];
+ DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
+ const int saveCountOffset = renderer.getSaveCount() - 1;
+ const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
+ for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+ DisplayListOp *op = mDisplayListData->displayListOps[i];
-#if DEBUG_DISPLAY_LIST
- op->output(level + 1);
-#endif
- logBuffer.writeCommand(level, op->name());
- handler(op, saveCountOffset, properties().getClipToBounds());
+ #if DEBUG_DISPLAY_LIST
+ op->output(level + 1);
+ #endif
+ logBuffer.writeCommand(level, op->name());
+ handler(op, saveCountOffset, properties().getClipToBounds());
- if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
- issueOperationsOfProjectedChildren(renderer, handler);
+ if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
+ issueOperationsOfProjectedChildren(renderer, handler);
+ }
}
- }
- // for 3d root, draw children with positive z values
- issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+ // for 3d root, draw children with positive z values
+ issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+ }
}
DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 393d4ea..b2fe849 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -39,6 +39,7 @@
#include <androidfw/ResourceTypes.h>
+#include "DamageAccumulator.h"
#include "Debug.h"
#include "Matrix.h"
#include "DeferredDisplayList.h"
@@ -125,6 +126,10 @@
return mDisplayListData && mDisplayListData->hasDrawOps;
}
+ bool hasProjectionReceiver() const {
+ return mDisplayListData && mDisplayListData->projectionReceiveIndex >= 0;
+ }
+
const char* getName() const {
return mName.string();
}
@@ -249,9 +254,13 @@
};
void prepareTreeImpl(TreeInfo& info);
- void pushStagingChanges(TreeInfo& info);
+ void pushStagingPropertiesChanges(TreeInfo& info);
+ void pushStagingDisplayListChanges(TreeInfo& info);
void evaluateAnimations(TreeInfo& info);
void prepareSubTree(TreeInfo& info, DisplayListData* subtree);
+ void applyLayerPropertiesToLayer(TreeInfo& info);
+ void prepareLayer(TreeInfo& info);
+ void pushLayerUpdate(TreeInfo& info);
String8 mName;
@@ -267,6 +276,10 @@
std::set< sp<BaseRenderNodeAnimator> > mStagingAnimators;
std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
+ // Owned by RT. Lifecycle is managed by prepareTree(), with the exception
+ // being in ~RenderNode() which may happen on any thread.
+ Layer* mLayer;
+
/**
* Draw time state - these properties are only set and used during rendering
*/
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 6163df5..8848b2f 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -21,16 +21,59 @@
#include <utils/Trace.h>
#include <SkCanvas.h>
+#include <SkColorFilter.h>
#include <SkMatrix.h>
#include <SkPath.h>
#include <SkPathOps.h>
#include "Matrix.h"
+#include "OpenGLRenderer.h"
#include "utils/MathUtils.h"
namespace android {
namespace uirenderer {
+LayerProperties::LayerProperties()
+ : mType(kLayerTypeNone)
+ , mColorFilter(NULL) {
+ reset();
+}
+
+LayerProperties::~LayerProperties() {
+ setType(kLayerTypeNone);
+}
+
+void LayerProperties::reset() {
+ mOpaque = false;
+ setFromPaint(NULL);
+}
+
+bool LayerProperties::setColorFilter(SkColorFilter* filter) {
+ if (mColorFilter == filter) return false;
+ SkRefCnt_SafeAssign(mColorFilter, filter);
+ return true;
+}
+
+bool LayerProperties::setFromPaint(const SkPaint* paint) {
+ bool changed = false;
+ SkXfermode::Mode mode;
+ int alpha;
+ OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
+ changed |= setAlpha(static_cast<uint8_t>(alpha));
+ changed |= setXferMode(mode);
+ changed |= setColorFilter(paint ? paint->getColorFilter() : NULL);
+ return changed;
+}
+
+LayerProperties& LayerProperties::operator=(const LayerProperties& other) {
+ setType(other.type());
+ setOpaque(other.opaque());
+ setAlpha(other.alpha());
+ setXferMode(other.xferMode());
+ setColorFilter(other.colorFilter());
+ return *this;
+}
+
RenderProperties::PrimitiveFields::PrimitiveFields()
: mClipToBounds(true)
, mProjectBackwards(false)
@@ -44,10 +87,8 @@
, mPivotX(0), mPivotY(0)
, mLeft(0), mTop(0), mRight(0), mBottom(0)
, mWidth(0), mHeight(0)
- , mScrollX(0), mScrollY(0)
, mPivotExplicitlySet(false)
- , mMatrixOrPivotDirty(false)
- , mCaching(false) {
+ , mMatrixOrPivotDirty(false) {
}
RenderProperties::ComputedFields::ComputedFields()
@@ -74,6 +115,7 @@
setStaticMatrix(other.getStaticMatrix());
setAnimationMatrix(other.getAnimationMatrix());
setCameraDistance(other.getCameraDistance());
+ mLayerProperties = other.layerProperties();
// Force recalculation of the matrix, since other's dirty bit may be clear
mPrimitiveFields.mMatrixOrPivotDirty = true;
@@ -104,9 +146,9 @@
}
}
- bool clipToBoundsNeeded = mPrimitiveFields.mCaching ? false : mPrimitiveFields.mClipToBounds;
+ bool clipToBoundsNeeded = layerProperties().type() != kLayerTypeNone ? false : mPrimitiveFields.mClipToBounds;
if (mPrimitiveFields.mAlpha < 1) {
- if (mPrimitiveFields.mCaching) {
+ if (layerProperties().type() != kLayerTypeNone) {
ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
} else if (!mPrimitiveFields.mHasOverlappingRendering) {
ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index c294f38..227d56e 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -21,6 +21,7 @@
#include <vector>
#include <cutils/compiler.h>
#include <androidfw/ResourceTypes.h>
+#include <utils/Log.h>
#include <SkCamera.h>
#include <SkMatrix.h>
@@ -30,8 +31,10 @@
#include "Rect.h"
#include "RevealClip.h"
#include "Outline.h"
+#include "utils/MathUtils.h"
class SkBitmap;
+class SkColorFilter;
class SkPaint;
namespace android {
@@ -39,15 +42,95 @@
class Matrix4;
class RenderNode;
+class RenderProperties;
// The __VA_ARGS__ will be executed if a & b are not equal
#define RP_SET(a, b, ...) (a != b ? (a = b, ##__VA_ARGS__, true) : false)
#define RP_SET_AND_DIRTY(a, b) RP_SET(a, b, mPrimitiveFields.mMatrixOrPivotDirty = true)
+// Keep in sync with View.java:LAYER_TYPE_*
+enum LayerType {
+ kLayerTypeNone = 0,
+ // Although we cannot build the software layer directly (must be done at
+ // record time), this information is used when applying alpha.
+ kLayerTypeSoftware = 1,
+ kLayerTypeRenderLayer = 2,
+ // TODO: LayerTypeSurfaceTexture? Maybe?
+};
+
+class ANDROID_API LayerProperties {
+public:
+ bool setType(LayerType type) {
+ if (RP_SET(mType, type)) {
+ reset();
+ return true;
+ }
+ return false;
+ }
+
+ LayerType type() const {
+ return mType;
+ }
+
+ bool setOpaque(bool opaque) {
+ return RP_SET(mOpaque, opaque);
+ }
+
+ bool opaque() const {
+ return mOpaque;
+ }
+
+ bool setAlpha(uint8_t alpha) {
+ return RP_SET(mAlpha, alpha);
+ }
+
+ uint8_t alpha() const {
+ return mAlpha;
+ }
+
+ bool setXferMode(SkXfermode::Mode mode) {
+ return RP_SET(mMode, mode);
+ }
+
+ SkXfermode::Mode xferMode() const {
+ return mMode;
+ }
+
+ bool setColorFilter(SkColorFilter* filter);
+
+ SkColorFilter* colorFilter() const {
+ return mColorFilter;
+ }
+
+ // Sets alpha, xfermode, and colorfilter from an SkPaint
+ // paint may be NULL, in which case defaults will be set
+ bool setFromPaint(const SkPaint* paint);
+
+ bool needsBlending() const {
+ return !opaque() || alpha() < 255;
+ }
+
+ LayerProperties& operator=(const LayerProperties& other);
+
+private:
+ LayerProperties();
+ ~LayerProperties();
+ void reset();
+
+ friend class RenderProperties;
+
+ LayerType mType;
+ // Whether or not that Layer's content is opaque, doesn't include alpha
+ bool mOpaque;
+ uint8_t mAlpha;
+ SkXfermode::Mode mMode;
+ SkColorFilter* mColorFilter;
+};
+
/*
* Data structure that holds the properties for a RenderNode
*/
-class RenderProperties {
+class ANDROID_API RenderProperties {
public:
RenderProperties();
virtual ~RenderProperties();
@@ -200,6 +283,7 @@
}
bool setScaleX(float scaleX) {
+ LOG_ALWAYS_FATAL_IF(scaleX > 1000000, "invalid scaleX %e", scaleX);
return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX);
}
@@ -208,6 +292,7 @@
}
bool setScaleY(float scaleY) {
+ LOG_ALWAYS_FATAL_IF(scaleY > 1000000, "invalid scaleY %e", scaleY);
return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY);
}
@@ -366,26 +451,6 @@
return false;
}
- bool setScrollX(int scrollX) {
- return RP_SET(mPrimitiveFields.mScrollX, scrollX);
- }
-
- bool setScrollY(int scrollY) {
- return RP_SET(mPrimitiveFields.mScrollY, scrollY);
- }
-
- int getScrollX() const {
- return mPrimitiveFields.mScrollX;
- }
-
- int getScrollY() const {
- return mPrimitiveFields.mScrollY;
- }
-
- bool setCaching(bool caching) {
- return RP_SET(mPrimitiveFields.mCaching, caching);
- }
-
int getWidth() const {
return mPrimitiveFields.mWidth;
}
@@ -412,10 +477,6 @@
return mComputedFields.mTransformMatrix;
}
- bool getCaching() const {
- return mPrimitiveFields.mCaching;
- }
-
bool getClipToBounds() const {
return mPrimitiveFields.mClipToBounds;
}
@@ -438,7 +499,7 @@
void debugOutputProperties(const int level) const;
- ANDROID_API void updateMatrix();
+ void updateMatrix();
bool hasClippingPath() const {
return mPrimitiveFields.mRevealClip.willClip();
@@ -461,6 +522,23 @@
return mPrimitiveFields.mRevealClip;
}
+ const LayerProperties& layerProperties() const {
+ return mLayerProperties;
+ }
+
+ LayerProperties& mutateLayerProperties() {
+ return mLayerProperties;
+ }
+
+ // Returns true if damage calculations should be clipped to bounds
+ // TODO: Figure out something better for getZ(), as children should still be
+ // clipped to this RP's bounds. But as we will damage -INT_MAX to INT_MAX
+ // for this RP's getZ() anyway, this can be optimized when we have a
+ // Z damage estimate instead of INT_MAX
+ bool getClipDamageToBounds() const {
+ return getClipToBounds() && (getZ() <= 0 || getOutline().isEmpty());
+ }
+
private:
// Rendering properties
@@ -481,14 +559,13 @@
float mPivotX, mPivotY;
int mLeft, mTop, mRight, mBottom;
int mWidth, mHeight;
- int mScrollX, mScrollY;
bool mPivotExplicitlySet;
bool mMatrixOrPivotDirty;
- bool mCaching;
} mPrimitiveFields;
SkMatrix* mStaticMatrix;
SkMatrix* mAnimationMatrix;
+ LayerProperties mLayerProperties;
/**
* These fields are all generated from other properties and are not set directly.
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index 2f714a1..30c6f5d 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -34,7 +34,7 @@
return a > b ? a : b;
}
-VertexBufferMode ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque,
+void ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque,
const Vector3* casterPolygon, int casterVertexCount,
const Vector3& centroid3d, const Rect& casterBounds,
const Rect& localClip, float maxZ, VertexBuffer& shadowVertexBuffer) {
@@ -57,16 +57,15 @@
#if DEBUG_SHADOW
ALOGD("Ambient shadow is out of clip rect!");
#endif
- return kVertexBufferMode_OnePolyRingShadow;
+ return;
}
- return AmbientShadow::createAmbientShadow(isCasterOpaque, casterPolygon,
+ AmbientShadow::createAmbientShadow(isCasterOpaque, casterPolygon,
casterVertexCount, centroid3d, heightFactor, geomFactor,
shadowVertexBuffer);
-
}
-VertexBufferMode ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
+void ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
const Vector3* casterPolygon, int casterVertexCount,
const mat4& receiverTransform, const Vector3& lightCenter, int lightRadius,
const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer) {
@@ -107,19 +106,17 @@
#if DEBUG_SHADOW
ALOGD("Spot shadow is out of clip rect!");
#endif
- return kVertexBufferMode_OnePolyRingShadow;
+ return;
}
- VertexBufferMode mode = SpotShadow::createSpotShadow(isCasterOpaque,
+ SpotShadow::createSpotShadow(isCasterOpaque,
casterPolygon, casterVertexCount, adjustedLightCenter, lightRadius,
lightVertexCount, shadowVertexBuffer);
-
#if DEBUG_SHADOW
if(shadowVertexBuffer.getVertexCount() <= 0) {
ALOGD("Spot shadow generation failed %d", shadowVertexBuffer.getVertexCount());
}
#endif
- return mode;
}
void ShadowTessellator::generateShadowIndices(uint16_t* shadowIndices) {
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index a1606ad..cb65df5 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -66,12 +66,12 @@
class ShadowTessellator {
public:
- static VertexBufferMode tessellateAmbientShadow(bool isCasterOpaque,
+ static void tessellateAmbientShadow(bool isCasterOpaque,
const Vector3* casterPolygon, int casterVertexCount,
const Vector3& centroid3d, const Rect& casterBounds,
const Rect& localClip, float maxZ, VertexBuffer& shadowVertexBuffer);
- static VertexBufferMode tessellateSpotShadow(bool isCasterOpaque,
+ static void tessellateSpotShadow(bool isCasterOpaque,
const Vector3* casterPolygon, int casterVertexCount,
const mat4& receiverTransform, const Vector3& lightCenter, int lightRadius,
const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer);
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index 3ebe7b4..06f6204 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -500,14 +500,14 @@
* empty strip if error.
*
*/
-VertexBufferMode SpotShadow::createSpotShadow(bool isCasterOpaque, const Vector3* poly,
+void SpotShadow::createSpotShadow(bool isCasterOpaque, const Vector3* poly,
int polyLength, const Vector3& lightCenter, float lightSize,
int lightVertexCount, VertexBuffer& retStrips) {
Vector3 light[lightVertexCount * 3];
computeLightPolygon(lightVertexCount, lightCenter, lightSize, light);
computeSpotShadow(isCasterOpaque, light, lightVertexCount, lightCenter, poly,
polyLength, retStrips);
- return kVertexBufferMode_TwoPolyRingShadow;
+ retStrips.setMode(VertexBuffer::kTwoPolyRingShadow);
}
/**
diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h
index fb3e6d5..d65ea89 100644
--- a/libs/hwui/SpotShadow.h
+++ b/libs/hwui/SpotShadow.h
@@ -26,7 +26,7 @@
class SpotShadow {
public:
- static VertexBufferMode createSpotShadow(bool isCasterOpaque, const Vector3* poly,
+ static void createSpotShadow(bool isCasterOpaque, const Vector3* poly,
int polyLength, const Vector3& lightCenter, float lightSize,
int lightVertexCount, VertexBuffer& retStrips);
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
index fae25a6..95c0ee5 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -101,6 +101,10 @@
// Matrix
///////////////////////////////////////////////////////////////////////////////
+void StatefulBaseRenderer::getMatrix(Matrix4* matrix) const {
+ matrix->load(*(mSnapshot->transform));
+}
+
void StatefulBaseRenderer::getMatrix(SkMatrix* matrix) const {
mSnapshot->transform->copyTo(*matrix);
}
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
index f38c752..e8e024f 100644
--- a/libs/hwui/StatefulBaseRenderer.h
+++ b/libs/hwui/StatefulBaseRenderer.h
@@ -69,6 +69,7 @@
// int alpha, SkXfermode::Mode mode, int flags);
// Matrix
+ void getMatrix(Matrix4* outMatrix) const;
virtual void getMatrix(SkMatrix* outMatrix) const;
virtual void translate(float dx, float dy, float dz = 0.0f);
virtual void rotate(float degrees);
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
new file mode 100644
index 0000000..ef3d0d7
--- /dev/null
+++ b/libs/hwui/TessellationCache.cpp
@@ -0,0 +1,485 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+#define ATRACE_TAG ATRACE_TAG_VIEW
+
+#include <utils/JenkinsHash.h>
+#include <utils/Trace.h>
+
+#include "Caches.h"
+#include "OpenGLRenderer.h"
+#include "PathTessellator.h"
+#include "ShadowTessellator.h"
+#include "TessellationCache.h"
+
+#include "thread/Signal.h"
+#include "thread/Task.h"
+#include "thread/TaskProcessor.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Cache entries
+///////////////////////////////////////////////////////////////////////////////
+
+TessellationCache::Description::Description()
+ : type(kNone)
+ , aa(false)
+ , cap(SkPaint::kDefault_Cap)
+ , style(SkPaint::kFill_Style)
+ , strokeWidth(1.0f) {
+ memset(&shape, 0, sizeof(Shape));
+}
+
+TessellationCache::Description::Description(Type type)
+ : type(type)
+ , aa(false)
+ , cap(SkPaint::kDefault_Cap)
+ , style(SkPaint::kFill_Style)
+ , strokeWidth(1.0f) {
+ memset(&shape, 0, sizeof(Shape));
+}
+
+TessellationCache::Description::Description(Type type, const SkPaint* paint)
+ : type(type)
+ , aa(paint->isAntiAlias())
+ , cap(paint->getStrokeCap())
+ , style(paint->getStyle())
+ , strokeWidth(paint->getStrokeWidth()) {
+ memset(&shape, 0, sizeof(Shape));
+}
+
+hash_t TessellationCache::Description::hash() const {
+ uint32_t hash = JenkinsHashMix(0, type);
+ hash = JenkinsHashMix(hash, aa);
+ hash = JenkinsHashMix(hash, cap);
+ hash = JenkinsHashMix(hash, style);
+ hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
+ hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape));
+ return JenkinsHashWhiten(hash);
+}
+
+TessellationCache::ShadowDescription::ShadowDescription()
+ : nodeKey(NULL) {
+ memset(&matrixData, 0, 16 * sizeof(float));
+}
+
+TessellationCache::ShadowDescription::ShadowDescription(const void* nodeKey, const Matrix4* drawTransform)
+ : nodeKey(nodeKey) {
+ memcpy(&matrixData, drawTransform->data, 16 * sizeof(float));
+}
+
+hash_t TessellationCache::ShadowDescription::hash() const {
+ uint32_t hash = JenkinsHashMixBytes(0, (uint8_t*) &nodeKey, sizeof(const void*));
+ hash = JenkinsHashMixBytes(hash, (uint8_t*) &matrixData, 16 * sizeof(float));
+ return JenkinsHashWhiten(hash);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// General purpose tessellation task processing
+///////////////////////////////////////////////////////////////////////////////
+
+class TessellationCache::TessellationTask : public Task<VertexBuffer*> {
+public:
+ TessellationTask(Tessellator tessellator, const Description& description,
+ const SkPaint* paint)
+ : tessellator(tessellator)
+ , description(description)
+ , paint(*paint) {
+ }
+
+ ~TessellationTask() {}
+
+ Tessellator tessellator;
+ Description description;
+
+ //copied, since input paint may not be immutable
+ const SkPaint paint;
+};
+
+class TessellationCache::TessellationProcessor : public TaskProcessor<VertexBuffer*> {
+public:
+ TessellationProcessor(Caches& caches)
+ : TaskProcessor<VertexBuffer*>(&caches.tasks) {}
+ ~TessellationProcessor() {}
+
+ virtual void onProcess(const sp<Task<VertexBuffer*> >& task) {
+ TessellationTask* t = static_cast<TessellationTask*>(task.get());
+ ATRACE_NAME("shape tessellation");
+ VertexBuffer* buffer = t->tessellator(t->description, t->paint);
+ t->setResult(buffer);
+ }
+};
+
+struct TessellationCache::Buffer {
+public:
+ Buffer(const sp<Task<VertexBuffer*> >& task)
+ : mTask(task)
+ , mBuffer(NULL) {
+ }
+
+ ~Buffer() {
+ mTask.clear();
+ delete mBuffer;
+ }
+
+ unsigned int getSize() {
+ blockOnPrecache();
+ return mBuffer->getSize();
+ }
+
+ const VertexBuffer* getVertexBuffer() {
+ blockOnPrecache();
+ return mBuffer;
+ }
+
+private:
+ void blockOnPrecache() {
+ if (mTask != NULL) {
+ mBuffer = mTask->getResult();
+ LOG_ALWAYS_FATAL_IF(mBuffer == NULL, "Failed to precache");
+ mTask.clear();
+ }
+ }
+ sp<Task<VertexBuffer*> > mTask;
+ VertexBuffer* mBuffer;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Shadow tessellation task processing
+///////////////////////////////////////////////////////////////////////////////
+
+class ShadowTask : public Task<TessellationCache::vertexBuffer_pair_t*> {
+public:
+ ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
+ const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
+ const Vector3& lightCenter, float lightRadius)
+ : drawTransform(*drawTransform)
+ , localClip(localClip)
+ , opaque(opaque)
+ , casterPerimeter(*casterPerimeter)
+ , transformXY(*transformXY)
+ , transformZ(*transformZ)
+ , lightCenter(lightCenter)
+ , lightRadius(lightRadius) {
+ }
+
+ ~ShadowTask() {
+ TessellationCache::vertexBuffer_pair_t* bufferPair = getResult();
+ delete bufferPair->getFirst();
+ delete bufferPair->getSecond();
+ delete bufferPair;
+ }
+
+ /* Note - we deep copy all task parameters, because *even though* pointers into Allocator
+ * controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame,
+ * certain Allocators are destroyed before trim() is called to flush incomplete tasks.
+ *
+ * These deep copies could be avoided, long term, by cancelling or flushing outstanding tasks
+ * before tearning down single-frame LinearAllocators.
+ */
+ const Matrix4 drawTransform;
+ const Rect localClip;
+ bool opaque;
+ const SkPath casterPerimeter;
+ const Matrix4 transformXY;
+ const Matrix4 transformZ;
+ const Vector3 lightCenter;
+ const float lightRadius;
+};
+
+static void mapPointFakeZ(Vector3& point, const mat4* transformXY, const mat4* transformZ) {
+ // map z coordinate with true 3d matrix
+ point.z = transformZ->mapZ(point);
+
+ // map x,y coordinates with draw/Skia matrix
+ transformXY->mapPoint(point.x, point.y);
+}
+
+static void tessellateShadows(
+ const Matrix4* drawTransform, const Rect* localClip,
+ bool isCasterOpaque, const SkPath* casterPerimeter,
+ const Matrix4* casterTransformXY, const Matrix4* casterTransformZ,
+ const Vector3& lightCenter, float lightRadius,
+ VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer) {
+
+ // tessellate caster outline into a 2d polygon
+ Vector<Vertex> casterVertices2d;
+ const float casterRefinementThresholdSquared = 20.0f; // TODO: experiment with this value
+ PathTessellator::approximatePathOutlineVertices(*casterPerimeter,
+ casterRefinementThresholdSquared, casterVertices2d);
+ if (!ShadowTessellator::isClockwisePath(*casterPerimeter)) {
+ ShadowTessellator::reverseVertexArray(casterVertices2d.editArray(),
+ casterVertices2d.size());
+ }
+
+ if (casterVertices2d.size() == 0) return;
+
+ // map 2d caster poly into 3d
+ const int casterVertexCount = casterVertices2d.size();
+ Vector3 casterPolygon[casterVertexCount];
+ float minZ = FLT_MAX;
+ float maxZ = -FLT_MAX;
+ for (int i = 0; i < casterVertexCount; i++) {
+ const Vertex& point2d = casterVertices2d[i];
+ casterPolygon[i] = Vector3(point2d.x, point2d.y, 0);
+ mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ);
+ minZ = fmin(minZ, casterPolygon[i].z);
+ maxZ = fmax(maxZ, casterPolygon[i].z);
+ }
+
+ // map the centroid of the caster into 3d
+ Vector2 centroid = ShadowTessellator::centroid2d(
+ reinterpret_cast<const Vector2*>(casterVertices2d.array()),
+ casterVertexCount);
+ Vector3 centroid3d(centroid.x, centroid.y, 0);
+ mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ);
+
+ // if the caster intersects the z=0 plane, lift it in Z so it doesn't
+ if (minZ < SHADOW_MIN_CASTER_Z) {
+ float casterLift = SHADOW_MIN_CASTER_Z - minZ;
+ for (int i = 0; i < casterVertexCount; i++) {
+ casterPolygon[i].z += casterLift;
+ }
+ centroid3d.z += casterLift;
+ }
+
+ // Check whether we want to draw the shadow at all by checking the caster's bounds against clip.
+ // We only have ortho projection, so we can just ignore the Z in caster for
+ // simple rejection calculation.
+ Rect casterBounds(casterPerimeter->getBounds());
+ casterTransformXY->mapRect(casterBounds);
+
+ // actual tessellation of both shadows
+ ShadowTessellator::tessellateAmbientShadow(
+ isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
+ casterBounds, *localClip, maxZ, ambientBuffer);
+
+ ShadowTessellator::tessellateSpotShadow(
+ isCasterOpaque, casterPolygon, casterVertexCount,
+ *drawTransform, lightCenter, lightRadius, casterBounds, *localClip,
+ spotBuffer);
+
+ // TODO: set ambientBuffer & spotBuffer's bounds for correct layer damage
+}
+
+class ShadowProcessor : public TaskProcessor<TessellationCache::vertexBuffer_pair_t*> {
+public:
+ ShadowProcessor(Caches& caches)
+ : TaskProcessor<TessellationCache::vertexBuffer_pair_t*>(&caches.tasks) {}
+ ~ShadowProcessor() {}
+
+ virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t*> >& task) {
+ ShadowTask* t = static_cast<ShadowTask*>(task.get());
+ ATRACE_NAME("shadow tessellation");
+
+ VertexBuffer* ambientBuffer = new VertexBuffer;
+ VertexBuffer* spotBuffer = new VertexBuffer;
+ tessellateShadows(&t->drawTransform, &t->localClip, t->opaque, &t->casterPerimeter,
+ &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius,
+ *ambientBuffer, *spotBuffer);
+
+ t->setResult(new TessellationCache::vertexBuffer_pair_t(ambientBuffer, spotBuffer));
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Cache constructor/destructor
+///////////////////////////////////////////////////////////////////////////////
+
+TessellationCache::TessellationCache()
+ : mSize(0)
+ , mMaxSize(MB(DEFAULT_VERTEX_CACHE_SIZE))
+ , mCache(LruCache<Description, Buffer*>::kUnlimitedCapacity)
+ , mShadowCache(LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get(PROPERTY_VERTEX_CACHE_SIZE, property, NULL) > 0) {
+ INIT_LOGD(" Setting %s cache size to %sMB", name, property);
+ setMaxSize(MB(atof(property)));
+ } else {
+ INIT_LOGD(" Using default %s cache size of %.2fMB", name, DEFAULT_VERTEX_CACHE_SIZE);
+ }
+
+ mCache.setOnEntryRemovedListener(&mBufferRemovedListener);
+ mShadowCache.setOnEntryRemovedListener(&mBufferPairRemovedListener);
+ mDebugEnabled = readDebugLevel() & kDebugCaches;
+}
+
+TessellationCache::~TessellationCache() {
+ mCache.clear();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Size management
+///////////////////////////////////////////////////////////////////////////////
+
+uint32_t TessellationCache::getSize() {
+ LruCache<Description, Buffer*>::Iterator iter(mCache);
+ uint32_t size = 0;
+ while (iter.next()) {
+ size += iter.value()->getSize();
+ }
+ return size;
+}
+
+uint32_t TessellationCache::getMaxSize() {
+ return mMaxSize;
+}
+
+void TessellationCache::setMaxSize(uint32_t maxSize) {
+ mMaxSize = maxSize;
+ while (mSize > mMaxSize) {
+ mCache.removeOldest();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Caching
+///////////////////////////////////////////////////////////////////////////////
+
+
+void TessellationCache::trim() {
+ uint32_t size = getSize();
+ while (size > mMaxSize) {
+ size -= mCache.peekOldestValue()->getSize();
+ mCache.removeOldest();
+ }
+ mShadowCache.clear();
+}
+
+void TessellationCache::clear() {
+ mCache.clear();
+ mShadowCache.clear();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Callbacks
+///////////////////////////////////////////////////////////////////////////////
+
+void TessellationCache::BufferRemovedListener::operator()(Description& description,
+ Buffer*& buffer) {
+ delete buffer;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Shadows
+///////////////////////////////////////////////////////////////////////////////
+
+void TessellationCache::precacheShadows(const Matrix4* drawTransform, const Rect& localClip,
+ bool opaque, const SkPath* casterPerimeter,
+ const Matrix4* transformXY, const Matrix4* transformZ,
+ const Vector3& lightCenter, float lightRadius) {
+ ShadowDescription key(casterPerimeter, drawTransform);
+
+ sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque,
+ casterPerimeter, transformXY, transformZ, lightCenter, lightRadius);
+ if (mShadowProcessor == NULL) {
+ mShadowProcessor = new ShadowProcessor(Caches::getInstance());
+ }
+ mShadowProcessor->add(task);
+
+ task->incStrong(NULL); // not using sp<>s, so manually ref while in the cache
+ mShadowCache.put(key, task.get());
+}
+
+void TessellationCache::getShadowBuffers(const Matrix4* drawTransform, const Rect& localClip,
+ bool opaque, const SkPath* casterPerimeter,
+ const Matrix4* transformXY, const Matrix4* transformZ,
+ const Vector3& lightCenter, float lightRadius, vertexBuffer_pair_t& outBuffers) {
+ ShadowDescription key(casterPerimeter, drawTransform);
+ ShadowTask* task = static_cast<ShadowTask*>(mShadowCache.get(key));
+ if (!task) {
+ precacheShadows(drawTransform, localClip, opaque, casterPerimeter,
+ transformXY, transformZ, lightCenter, lightRadius);
+ task = static_cast<ShadowTask*>(mShadowCache.get(key));
+ }
+ LOG_ALWAYS_FATAL_IF(task == NULL, "shadow not precached");
+ outBuffers = *(task->getResult());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Tessellation precaching
+///////////////////////////////////////////////////////////////////////////////
+
+static VertexBuffer* tessellatePath(const SkPath& path, const SkPaint* paint,
+ float scaleX, float scaleY) {
+ VertexBuffer* buffer = new VertexBuffer();
+ Matrix4 matrix;
+ matrix.loadScale(scaleX, scaleY, 1);
+ PathTessellator::tessellatePath(path, paint, matrix, *buffer);
+ return buffer;
+}
+
+TessellationCache::Buffer* TessellationCache::getOrCreateBuffer(
+ const Description& entry, Tessellator tessellator, const SkPaint* paint) {
+ Buffer* buffer = mCache.get(entry);
+ if (!buffer) {
+ // not cached, enqueue a task to fill the buffer
+ sp<TessellationTask> task = new TessellationTask(tessellator, entry, paint);
+ buffer = new Buffer(task);
+
+ if (mProcessor == NULL) {
+ mProcessor = new TessellationProcessor(Caches::getInstance());
+ }
+ mProcessor->add(task);
+ mCache.put(entry, buffer);
+ }
+ return buffer;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Rounded rects
+///////////////////////////////////////////////////////////////////////////////
+
+static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& description,
+ const SkPaint& paint) {
+ SkRect rect = SkRect::MakeWH(description.shape.roundRect.mWidth,
+ description.shape.roundRect.mHeight);
+ float rx = description.shape.roundRect.mRx;
+ float ry = description.shape.roundRect.mRy;
+ if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) {
+ float outset = paint.getStrokeWidth() / 2;
+ rect.outset(outset, outset);
+ rx += outset;
+ ry += outset;
+ }
+ SkPath path;
+ path.addRoundRect(rect, rx, ry);
+ return tessellatePath(path, &paint,
+ description.shape.roundRect.mScaleX, description.shape.roundRect.mScaleY);
+}
+
+TessellationCache::Buffer* TessellationCache::getRoundRectBuffer(const Matrix4& transform,
+ float width, float height, float rx, float ry, const SkPaint* paint) {
+ Description entry(Description::kRoundRect, paint);
+ entry.shape.roundRect.mWidth = width;
+ entry.shape.roundRect.mHeight = height;
+ entry.shape.roundRect.mRx = rx;
+ entry.shape.roundRect.mRy = ry;
+ PathTessellator::extractTessellationScales(transform,
+ &entry.shape.roundRect.mScaleX, &entry.shape.roundRect.mScaleY);
+
+ return getOrCreateBuffer(entry, &tessellateRoundRect, paint);
+}
+const VertexBuffer* TessellationCache::getRoundRect(const Matrix4& transform,
+ float width, float height, float rx, float ry, const SkPaint* paint) {
+ return getRoundRectBuffer(transform, width, height, rx, ry, paint)->getVertexBuffer();
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h
new file mode 100644
index 0000000..d4ff943
--- /dev/null
+++ b/libs/hwui/TessellationCache.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_TESSELLATION_CACHE_H
+#define ANDROID_HWUI_TESSELLATION_CACHE_H
+
+#include <utils/LruCache.h>
+#include <utils/Mutex.h>
+#include <utils/Vector.h>
+
+#include "Debug.h"
+#include "utils/Macros.h"
+#include "utils/Pair.h"
+#include "VertexBuffer.h"
+
+class SkBitmap;
+class SkCanvas;
+class SkPaint;
+class SkPath;
+struct SkRect;
+
+namespace android {
+namespace uirenderer {
+
+class Caches;
+
+///////////////////////////////////////////////////////////////////////////////
+// Classes
+///////////////////////////////////////////////////////////////////////////////
+
+class TessellationCache {
+public:
+ typedef Pair<VertexBuffer*, VertexBuffer*> vertexBuffer_pair_t;
+
+ struct Description {
+ DESCRIPTION_TYPE(Description);
+ enum Type {
+ kNone,
+ kRoundRect,
+ kAmbientShadow,
+ kSpotShadow
+ };
+
+ Type type;
+ bool aa;
+ SkPaint::Cap cap;
+ SkPaint::Style style;
+ float strokeWidth;
+ union Shape {
+ struct RoundRect {
+ float mScaleX;
+ float mScaleY;
+ float mWidth;
+ float mHeight;
+ float mRx;
+ float mRy;
+ } roundRect;
+ } shape;
+
+ Description();
+ Description(Type type);
+ Description(Type type, const SkPaint* paint);
+ hash_t hash() const;
+ };
+
+ struct ShadowDescription {
+ DESCRIPTION_TYPE(ShadowDescription);
+ const void* nodeKey;
+ float matrixData[16];
+
+ ShadowDescription();
+ ShadowDescription(const void* nodeKey, const Matrix4* drawTransform);
+ hash_t hash() const;
+ };
+
+ TessellationCache();
+ ~TessellationCache();
+
+ /**
+ * Clears the cache. This causes all TessellationBuffers to be deleted.
+ */
+ void clear();
+
+ /**
+ * Sets the maximum size of the cache in bytes.
+ */
+ void setMaxSize(uint32_t maxSize);
+ /**
+ * Returns the maximum size of the cache in bytes.
+ */
+ uint32_t getMaxSize();
+ /**
+ * Returns the current size of the cache in bytes.
+ */
+ uint32_t getSize();
+
+ /**
+ * Trims the contents of the cache, removing items until it's under its
+ * specified limit.
+ *
+ * Trimming is used for caches that support pre-caching from a worker
+ * thread. During pre-caching the maximum limit of the cache can be
+ * exceeded for the duration of the frame. It is therefore required to
+ * trim the cache at the end of the frame to keep the total amount of
+ * memory used under control.
+ *
+ * Also removes transient Shadow VertexBuffers, which aren't cached between frames.
+ */
+ void trim();
+
+ // TODO: precache/get for Oval, Lines, Points, etc.
+
+ void precacheRoundRect(const Matrix4& transform,
+ float width, float height, float rx, float ry, const SkPaint* paint) {
+ getRoundRectBuffer(transform, width, height, rx, ry, paint);
+ }
+ const VertexBuffer* getRoundRect(const Matrix4& transform,
+ float width, float height, float rx, float ry, const SkPaint* paint);
+
+ void precacheShadows(const Matrix4* drawTransform, const Rect& localClip,
+ bool opaque, const SkPath* casterPerimeter,
+ const Matrix4* transformXY, const Matrix4* transformZ,
+ const Vector3& lightCenter, float lightRadius);
+
+ void getShadowBuffers(const Matrix4* drawTransform, const Rect& localClip,
+ bool opaque, const SkPath* casterPerimeter,
+ const Matrix4* transformXY, const Matrix4* transformZ,
+ const Vector3& lightCenter, float lightRadius,
+ vertexBuffer_pair_t& outBuffers);
+
+private:
+ class Buffer;
+ class TessellationTask;
+ class TessellationProcessor;
+
+
+ typedef VertexBuffer* (*Tessellator)(const Description&, const SkPaint&);
+
+ Buffer* getRoundRectBuffer(const Matrix4& transform,
+ float width, float height, float rx, float ry, const SkPaint* paint);
+
+ Buffer* getOrCreateBuffer(const Description& entry,
+ Tessellator tessellator, const SkPaint* paint);
+
+ uint32_t mSize;
+ uint32_t mMaxSize;
+
+ bool mDebugEnabled;
+
+ mutable Mutex mLock;
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // General tessellation caching
+ ///////////////////////////////////////////////////////////////////////////////
+ sp<TaskProcessor<VertexBuffer*> > mProcessor;
+ LruCache<Description, Buffer*> mCache;
+ class BufferRemovedListener : public OnEntryRemoved<Description, Buffer*> {
+ void operator()(Description& description, Buffer*& buffer);
+ };
+ BufferRemovedListener mBufferRemovedListener;
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // Shadow tessellation caching
+ ///////////////////////////////////////////////////////////////////////////////
+ sp<TaskProcessor<vertexBuffer_pair_t*> > mShadowProcessor;
+
+ // holds a pointer, and implicit strong ref to each shadow task of the frame
+ LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*> mShadowCache;
+ class BufferPairRemovedListener : public OnEntryRemoved<ShadowDescription, Task<vertexBuffer_pair_t*>*> {
+ void operator()(ShadowDescription& description, Task<vertexBuffer_pair_t*>*& bufferPairTask) {
+ bufferPairTask->decStrong(NULL);
+ }
+ };
+ BufferPairRemovedListener mBufferPairRemovedListener;
+
+}; // class TessellationCache
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_PATH_CACHE_H
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 60b4b96..1001cae0 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -288,19 +288,19 @@
switch (bitmap->config()) {
case SkBitmap::kA8_Config:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(),
+ uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
texture->blend = true;
break;
case SkBitmap::kRGB_565_Config:
glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
- uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(),
+ uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
texture->width, texture->height, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
texture->blend = false;
break;
case SkBitmap::kARGB_8888_Config:
glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
- uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(),
+ uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
// Do this after calling getPixels() to make sure Skia's deferred
// decoding happened
@@ -340,27 +340,49 @@
SkCanvas canvas(rgbaBitmap);
canvas.drawBitmap(*bitmap, 0.0f, 0.0f, NULL);
- uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), width, height,
- GL_UNSIGNED_BYTE, rgbaBitmap.getPixels());
+ uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), rgbaBitmap.bytesPerPixel(),
+ width, height, GL_UNSIGNED_BYTE, rgbaBitmap.getPixels());
}
-void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride,
+void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
GLsizei width, GLsizei height, GLenum type, const GLvoid * data) {
- // TODO: With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
- // if the stride doesn't match the width
const bool useStride = stride != width && Extensions::getInstance().hasUnpackRowLength();
- if (useStride) {
- glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
- }
+ if ((stride == width) || useStride) {
+ if (useStride) {
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
+ }
- if (resize) {
- glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
+ if (resize) {
+ glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
+ }
+
+ if (useStride) {
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ }
} else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
- }
+ // With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
+ // if the stride doesn't match the width
- if (useStride) {
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ GLvoid * temp = (GLvoid *) malloc(width * height * bpp);
+ if (!temp) return;
+
+ uint8_t * pDst = (uint8_t *)temp;
+ uint8_t * pSrc = (uint8_t *)data;
+ for (GLsizei i = 0; i < height; i++) {
+ memcpy(pDst, pSrc, width * bpp);
+ pDst += width * bpp;
+ pSrc += stride * bpp;
+ }
+
+ if (resize) {
+ glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp);
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp);
+ }
+
+ free(temp);
}
}
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index e5b5c1a..61db5b0 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -142,7 +142,7 @@
void generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate = false);
void uploadLoFiTexture(bool resize, const SkBitmap* bitmap, uint32_t width, uint32_t height);
- void uploadToTexture(bool resize, GLenum format, GLsizei stride,
+ void uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
GLsizei width, GLsizei height, GLenum type, const GLvoid * data);
void init();
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 2096f98..0fc0cef 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -18,6 +18,7 @@
#include <utils/Timers.h>
+#include "DamageAccumulator.h"
#include "utils/Macros.h"
namespace android {
@@ -25,7 +26,7 @@
class BaseRenderNodeAnimator;
class AnimationListener;
-class DamageAccumulator;
+class OpenGLRenderer;
class AnimationHook {
public:
@@ -62,7 +63,8 @@
, frameTimeMs(0)
, animationHook(NULL)
, prepareTextures(mode == MODE_FULL)
- , damageAccumulator(0)
+ , damageAccumulator(NullDamageAccumulator::instance())
+ , renderer(0)
{}
const TraversalMode mode;
@@ -71,7 +73,11 @@
// TODO: Remove this? Currently this is used to signal to stop preparing
// textures if we run out of cache space.
bool prepareTextures;
- DamageAccumulator* damageAccumulator;
+ // Must not be null
+ IDamageAccumulator* damageAccumulator;
+ // The renderer that will be drawing the next frame. Use this to push any
+ // layer updates or similar. May be NULL.
+ OpenGLRenderer* renderer;
struct Out {
Out()
diff --git a/libs/hwui/VertexBuffer.h b/libs/hwui/VertexBuffer.h
index 8b6872e..55d566b 100644
--- a/libs/hwui/VertexBuffer.h
+++ b/libs/hwui/VertexBuffer.h
@@ -23,10 +23,18 @@
class VertexBuffer {
public:
- VertexBuffer():
- mBuffer(0),
- mVertexCount(0),
- mCleanupMethod(NULL)
+ enum Mode {
+ kStandard = 0,
+ kOnePolyRingShadow = 1,
+ kTwoPolyRingShadow = 2
+ };
+
+ VertexBuffer()
+ : mBuffer(0)
+ , mVertexCount(0)
+ , mByteCount(0)
+ , mMode(kStandard)
+ , mCleanupMethod(NULL)
{}
~VertexBuffer() {
@@ -37,7 +45,7 @@
This should be the only method used by the Tessellator. Subsequent calls to
alloc will allocate space within the first allocation (useful if you want to
eventually allocate multiple regions within a single VertexBuffer, such as
- with PathTessellator::tesselateLines())
+ with PathTessellator::tessellateLines())
*/
template <class TYPE>
TYPE* alloc(int vertexCount) {
@@ -52,6 +60,7 @@
return reallocBuffer;
}
mVertexCount = vertexCount;
+ mByteCount = mVertexCount * sizeof(TYPE);
mReallocBuffer = mBuffer = (void*)new TYPE[vertexCount];
mCleanupMethod = &(cleanup<TYPE>);
@@ -71,7 +80,13 @@
}
const void* getBuffer() const { return mBuffer; }
+ const Rect& getBounds() const { return mBounds; }
unsigned int getVertexCount() const { return mVertexCount; }
+ unsigned int getSize() const { return mByteCount; }
+ Mode getMode() const { return mMode; }
+
+ void setBounds(Rect bounds) { mBounds = bounds; }
+ void setMode(Mode mode) { mMode = mode; }
template <class TYPE>
void createDegenerateSeparators(int allocSize) {
@@ -88,8 +103,11 @@
delete[] (TYPE*)buffer;
}
+ Rect mBounds;
void* mBuffer;
unsigned int mVertexCount;
+ unsigned int mByteCount;
+ Mode mMode;
void* mReallocBuffer; // used for multi-allocation
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 8a5c857..dc1951b 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -440,6 +440,7 @@
info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
info.damageAccumulator = &mDamageAccumulator;
+ info.renderer = mCanvas;
mRootRenderNode->prepareTree(info);
int runningBehind = 0;
@@ -536,9 +537,12 @@
requireGlContext();
mode = DrawGlInfo::kModeProcess;
}
- (*functor)(mode, NULL);
if (mCanvas) {
+ mCanvas->interrupt();
+ }
+ (*functor)(mode, NULL);
+ if (mCanvas) {
mCanvas->resume();
}
}
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index bdfdd21..797566f 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -130,9 +130,6 @@
mContext->processLayerUpdate(mLayers[i].get(), info);
}
mLayers.clear();
- if (info.out.hasAnimations) {
- // TODO: Uh... crap?
- }
mContext->prepareTree(info);
if (info.out.hasAnimations) {
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index ded10a1..4988f19 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -47,7 +47,7 @@
#define SETUP_TASK(method) \
LOG_ALWAYS_FATAL_IF( METHOD_INVOKE_PAYLOAD_SIZE < sizeof(ARGS(method)), \
- "METHOD_INVOKE_PAYLOAD_SIZE %d is smaller than sizeof(" #method "Args) %d", \
+ "METHOD_INVOKE_PAYLOAD_SIZE %zu is smaller than sizeof(" #method "Args) %zu", \
METHOD_INVOKE_PAYLOAD_SIZE, sizeof(ARGS(method))); \
MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \
ARGS(method) *args = (ARGS(method) *) task->payload()
diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp
index 189895c..3d2b0d9 100644
--- a/libs/hwui/thread/TaskManager.cpp
+++ b/libs/hwui/thread/TaskManager.cpp
@@ -16,9 +16,10 @@
#include <sys/sysinfo.h>
+#include "TaskManager.h"
#include "Task.h"
#include "TaskProcessor.h"
-#include "TaskManager.h"
+#include "utils/MathUtils.h"
namespace android {
namespace uirenderer {
@@ -31,7 +32,8 @@
// Get the number of available CPUs. This value does not change over time.
int cpuCount = sysconf(_SC_NPROCESSORS_CONF);
- for (int i = 0; i < cpuCount / 2; i++) {
+ int workerCount = MathUtils::max(1, cpuCount / 2);
+ for (int i = 0; i < workerCount; i++) {
String8 name;
name.appendFormat("hwuiTask%d", i + 1);
mThreads.add(new WorkerThread(name));
diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h
index 14a3ec0..5b7c87c 100644
--- a/libs/hwui/utils/Macros.h
+++ b/libs/hwui/utils/Macros.h
@@ -21,5 +21,12 @@
Type(const Type&); \
void operator=(const Type&)
+#define DESCRIPTION_TYPE(Type) \
+ int compare(const Type& rhs) const { return memcmp(this, &rhs, sizeof(Type));} \
+ bool operator==(const Type& other) const { return compare(other) == 0; } \
+ bool operator!=(const Type& other) const { return compare(other) != 0; } \
+ friend inline int strictly_order_type(const Type& lhs, const Type& rhs) { return lhs.compare(rhs) < 0; } \
+ friend inline int compare_type(const Type& lhs, const Type& rhs) { return lhs.compare(rhs); } \
+ friend inline hash_t hash_type(const Type& entry) { return entry.hash(); }
#endif /* MACROS_H */
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index 997acde2..65f1663 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -38,6 +38,10 @@
return isZero(valueA - valueB);
}
+ inline static int max(int a, int b) {
+ return a > b ? a : b;
+ }
+
inline static int min(int a, int b) {
return a < b ? a : b;
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 88756d7..2f1e11e 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -50,12 +50,6 @@
*/
public class AudioManager {
- // If we should use the new sessions APIs.
- private final static boolean USE_SESSIONS = true;
- // If we should use the legacy APIs. If both are true information will be
- // duplicated through both paths. Currently this flag isn't used.
- private final static boolean USE_LEGACY = true;
-
private final Context mContext;
private long mVolumeKeyUpTime;
private final boolean mUseMasterVolume;
@@ -483,17 +477,8 @@
* or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
*/
public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
- if (USE_SESSIONS) {
- MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
- helper.sendMediaButtonEvent(keyEvent, false);
- } else {
- IAudioService service = getService();
- try {
- service.dispatchMediaKeyEvent(keyEvent);
- } catch (RemoteException e) {
- Log.e(TAG, "dispatchMediaKeyEvent threw exception ", e);
- }
- }
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+ helper.sendMediaButtonEvent(keyEvent, false);
}
/**
@@ -644,12 +629,8 @@
if (mUseMasterVolume) {
service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
} else {
- if (USE_SESSIONS) {
- MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
- helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
- } else {
- service.adjustVolume(direction, flags, mContext.getOpPackageName());
- }
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+ helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
}
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustVolume", e);
@@ -679,13 +660,8 @@
if (mUseMasterVolume) {
service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
} else {
- if (USE_SESSIONS) {
- MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
- helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
- } else {
- service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags,
- mContext.getOpPackageName());
- }
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+ helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
}
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustSuggestedStreamVolume", e);
@@ -1017,7 +993,7 @@
public void setMasterMute(boolean state, int flags) {
IAudioService service = getService();
try {
- service.setMasterMute(state, flags, mICallBack);
+ service.setMasterMute(state, flags, mContext.getOpPackageName(), mICallBack);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in setMasterMute", e);
}
@@ -1425,7 +1401,12 @@
* <var>false</var> to turn mute off
*/
public void setMicrophoneMute(boolean on){
- AudioSystem.muteMicrophone(on);
+ IAudioService service = getService();
+ try {
+ service.setMicrophoneMute(on, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setMicrophoneMute", e);
+ }
}
/**
@@ -1653,6 +1634,25 @@
}
}
+
+ /**
+ * Return a new audio session identifier not associated with any player or effect.
+ * It can for instance be used to create one of the {@link android.media.audiofx.AudioEffect}
+ * objects.
+ * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
+ * system failed to allocate a new session.
+ */
+ public int allocateAudioSessionId() {
+ int session = AudioSystem.newAudioSessionId();
+ if (session > 0) {
+ return session;
+ } else {
+ Log.e(TAG, "Failure to allocate a new audio session ID");
+ return ERROR;
+ }
+ }
+
+
/*
* Sets a generic audio configuration parameter. The use of these parameters
* are platform dependant, see libaudio
@@ -2191,16 +2191,15 @@
}
IAudioService service = getService();
try {
- // pi != null
+ // pi != null, this is currently still needed to support across
+ // reboot launching of the last app.
service.registerMediaButtonIntent(pi, eventReceiver,
eventReceiver == null ? mToken : null);
} catch (RemoteException e) {
Log.e(TAG, "Dead object in registerMediaButtonIntent"+e);
}
- if (USE_SESSIONS) {
- MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
- helper.addMediaButtonListener(pi, mContext);
- }
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+ helper.addMediaButtonListener(pi, mContext);
}
/**
@@ -2274,10 +2273,8 @@
} catch (RemoteException e) {
Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e);
}
- if (USE_SESSIONS) {
- MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
- helper.removeMediaButtonListener(pi);
- }
+ MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
+ helper.removeMediaButtonListener(pi);
}
/**
@@ -2291,20 +2288,7 @@
if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
return;
}
- IAudioService service = getService();
- try {
- int rcseId = service.registerRemoteControlClient(
- rcClient.getRcMediaIntent(), /* mediaIntent */
- rcClient.getIRemoteControlClient(),/* rcClient */
- // used to match media button event receiver and audio focus
- mContext.getPackageName()); /* packageName */
- rcClient.setRcseId(rcseId);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in registerRemoteControlClient"+e);
- }
- if (USE_SESSIONS) {
- rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(mContext));
- }
+ rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(mContext));
}
/**
@@ -2317,16 +2301,7 @@
if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
return;
}
- IAudioService service = getService();
- try {
- service.unregisterRemoteControlClient(rcClient.getRcMediaIntent(), /* mediaIntent */
- rcClient.getIRemoteControlClient()); /* rcClient */
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
- }
- if (USE_SESSIONS) {
- rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(mContext));
- }
+ rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(mContext));
}
/**
@@ -2344,20 +2319,8 @@
if (rctlr == null) {
return false;
}
- IAudioService service = getService();
- final RemoteController.OnClientUpdateListener l = rctlr.getUpdateListener();
- final ComponentName listenerComponent = new ComponentName(mContext, l.getClass());
- try {
- int[] artworkDimensions = rctlr.getArtworkSize();
- boolean reg = service.registerRemoteController(rctlr.getRcDisplay(),
- artworkDimensions[0]/*w*/, artworkDimensions[1]/*h*/,
- listenerComponent);
- rctlr.setIsRegistered(reg);
- return reg;
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in registerRemoteController " + e);
- return false;
- }
+ rctlr.startListeningToSessions();
+ return true;
}
/**
@@ -2369,13 +2332,7 @@
if (rctlr == null) {
return;
}
- IAudioService service = getService();
- try {
- service.unregisterRemoteControlDisplay(rctlr.getRcDisplay());
- rctlr.setIsRegistered(false);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in unregisterRemoteControlDisplay " + e);
- }
+ rctlr.stopListeningToSessions();
}
/**
@@ -2998,7 +2955,8 @@
/** @hide
*/
public static final int SUCCESS = AudioSystem.SUCCESS;
- /** @hide
+ /**
+ * A default error code.
*/
public static final int ERROR = AudioSystem.ERROR;
/** @hide
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 74f39b7..72f4a58 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -108,8 +108,7 @@
/** Debug volumes */
protected static final boolean DEBUG_VOL = false;
- /** Reroute calls to media session apis */
- private static final boolean USE_SESSIONS = true;
+ /** debug calls to media session apis */
private static final boolean DEBUG_SESSIONS = true;
/** Allow volume changes to set ringer mode to silent? */
@@ -1321,11 +1320,16 @@
}
/** @see AudioManager#setMasterMute(boolean, int) */
- public void setMasterMute(boolean state, int flags, IBinder cb) {
+ public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
if (mUseFixedVolume) {
return;
}
+ if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
+ callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ return;
+ }
+
if (state != AudioSystem.getMasterMute()) {
AudioSystem.setMasterMute(state);
// Post a persist master volume msg
@@ -1432,6 +1436,16 @@
}
}
+ /** @see AudioManager#setMicrophoneMute(boolean) */
+ public void setMicrophoneMute(boolean on, String callingPackage) {
+ if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
+ callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ return;
+ }
+
+ AudioSystem.muteMicrophone(on);
+ }
+
/** @see AudioManager#getRingerMode() */
public int getRingerMode() {
synchronized(mSettingsLock) {
@@ -4469,27 +4483,19 @@
}
public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
- if (USE_SESSIONS) {
- if (DEBUG_SESSIONS) {
- int pid = getCallingPid();
- Log.w(TAG, "Call to dispatchMediaKeyEvent from " + pid);
- }
- MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
- } else {
- mMediaFocusControl.dispatchMediaKeyEvent(keyEvent);
+ if (DEBUG_SESSIONS) {
+ int pid = getCallingPid();
+ Log.w(TAG, "Call to dispatchMediaKeyEvent from " + pid);
}
+ MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
}
public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
- if (USE_SESSIONS) {
- if (DEBUG_SESSIONS) {
- int pid = getCallingPid();
- Log.w(TAG, "Call to dispatchMediaKeyEventUnderWakelock from " + pid);
- }
- MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, true);
- } else {
- mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent);
+ if (DEBUG_SESSIONS) {
+ int pid = getCallingPid();
+ Log.w(TAG, "Call to dispatchMediaKeyEventUnderWakelock from " + pid);
}
+ MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, true);
}
//==========================================================================================
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index c8d64ce..9fbcd18 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -130,6 +130,11 @@
public static native boolean isSourceActive(int source);
/*
+ * Returns a new unused audio session ID
+ */
+ public static native int newAudioSessionId();
+
+ /*
* Sets a group generic audio configuration parameters. The use of these parameters
* are platform dependent, see libaudio
*
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index 511111c..f9e49c1 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -90,9 +90,14 @@
*/
public static final int QUALITY_QVGA = 7;
+ /**
+ * Quality level corresponding to the 2160p (3840x2160) resolution.
+ */
+ public static final int QUALITY_2160P = 8;
+
// Start and end of quality list
private static final int QUALITY_LIST_START = QUALITY_LOW;
- private static final int QUALITY_LIST_END = QUALITY_QVGA;
+ private static final int QUALITY_LIST_END = QUALITY_2160P;
/**
* Time lapse quality level corresponding to the lowest available resolution.
@@ -134,9 +139,14 @@
*/
public static final int QUALITY_TIME_LAPSE_QVGA = 1007;
+ /**
+ * Time lapse quality level corresponding to the 2160p (3840 x 2160) resolution.
+ */
+ public static final int QUALITY_TIME_LAPSE_2160P = 1008;
+
// Start and end of timelapse quality list
private static final int QUALITY_TIME_LAPSE_LIST_START = QUALITY_TIME_LAPSE_LOW;
- private static final int QUALITY_TIME_LAPSE_LIST_END = QUALITY_TIME_LAPSE_QVGA;
+ private static final int QUALITY_TIME_LAPSE_LIST_END = QUALITY_TIME_LAPSE_2160P;
/**
* Default recording duration in seconds before the session is terminated.
diff --git a/media/java/android/media/ClosedCaptionRenderer.java b/media/java/android/media/ClosedCaptionRenderer.java
new file mode 100644
index 0000000..ec33c5c
--- /dev/null
+++ b/media/java/android/media/ClosedCaptionRenderer.java
@@ -0,0 +1,1464 @@
+/*
+ * 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.media;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.text.style.CharacterStyle;
+import android.text.style.StyleSpan;
+import android.text.style.UnderlineSpan;
+import android.text.style.UpdateAppearance;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.CaptioningManager;
+import android.view.accessibility.CaptioningManager.CaptionStyle;
+import android.view.accessibility.CaptioningManager.CaptioningChangeListener;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Vector;
+
+/** @hide */
+public class ClosedCaptionRenderer extends SubtitleController.Renderer {
+ private final Context mContext;
+ private ClosedCaptionWidget mRenderingWidget;
+
+ public ClosedCaptionRenderer(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public boolean supports(MediaFormat format) {
+ if (format.containsKey(MediaFormat.KEY_MIME)) {
+ return format.getString(MediaFormat.KEY_MIME).equals(
+ MediaPlayer.MEDIA_MIMETYPE_TEXT_CEA_608);
+ }
+ return false;
+ }
+
+ @Override
+ public SubtitleTrack createTrack(MediaFormat format) {
+ if (mRenderingWidget == null) {
+ mRenderingWidget = new ClosedCaptionWidget(mContext);
+ }
+ return new ClosedCaptionTrack(mRenderingWidget, format);
+ }
+}
+
+/** @hide */
+class ClosedCaptionTrack extends SubtitleTrack {
+ private final ClosedCaptionWidget mRenderingWidget;
+ private final CCParser mCCParser;
+
+ ClosedCaptionTrack(ClosedCaptionWidget renderingWidget, MediaFormat format) {
+ super(format);
+
+ mRenderingWidget = renderingWidget;
+ mCCParser = new CCParser(renderingWidget);
+ }
+
+ @Override
+ public void onData(byte[] data, boolean eos, long runID) {
+ mCCParser.parse(data);
+ }
+
+ @Override
+ public RenderingWidget getRenderingWidget() {
+ return mRenderingWidget;
+ }
+
+ @Override
+ public void updateView(Vector<Cue> activeCues) {
+ // Overriding with NO-OP, CC rendering by-passes this
+ }
+}
+
+/**
+ * @hide
+ *
+ * CCParser processes CEA-608 closed caption data.
+ *
+ * It calls back into OnDisplayChangedListener upon
+ * display change with styled text for rendering.
+ *
+ */
+class CCParser {
+ public static final int MAX_ROWS = 15;
+ public static final int MAX_COLS = 32;
+
+ private static final String TAG = "CCParser";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static final int INVALID = -1;
+
+ // EIA-CEA-608: Table 70 - Control Codes
+ private static final int RCL = 0x20;
+ private static final int BS = 0x21;
+ private static final int AOF = 0x22;
+ private static final int AON = 0x23;
+ private static final int DER = 0x24;
+ private static final int RU2 = 0x25;
+ private static final int RU3 = 0x26;
+ private static final int RU4 = 0x27;
+ private static final int FON = 0x28;
+ private static final int RDC = 0x29;
+ private static final int TR = 0x2a;
+ private static final int RTD = 0x2b;
+ private static final int EDM = 0x2c;
+ private static final int CR = 0x2d;
+ private static final int ENM = 0x2e;
+ private static final int EOC = 0x2f;
+
+ // Transparent Space
+ private static final char TS = '\u00A0';
+
+ // Captioning Modes
+ private static final int MODE_UNKNOWN = 0;
+ private static final int MODE_PAINT_ON = 1;
+ private static final int MODE_ROLL_UP = 2;
+ private static final int MODE_POP_ON = 3;
+ private static final int MODE_TEXT = 4;
+
+ private final DisplayListener mListener;
+
+ private int mMode = MODE_PAINT_ON;
+ private int mRollUpSize = 4;
+
+ private CCMemory mDisplay = new CCMemory();
+ private CCMemory mNonDisplay = new CCMemory();
+ private CCMemory mTextMem = new CCMemory();
+
+ CCParser(DisplayListener listener) {
+ mListener = listener;
+ }
+
+ void parse(byte[] data) {
+ CCData[] ccData = CCData.fromByteArray(data);
+
+ for (int i = 0; i < ccData.length; i++) {
+ if (DEBUG) {
+ Log.d(TAG, ccData[i].toString());
+ }
+
+ if (handleCtrlCode(ccData[i])
+ || handleTabOffsets(ccData[i])
+ || handlePACCode(ccData[i])
+ || handleMidRowCode(ccData[i])) {
+ continue;
+ }
+
+ handleDisplayableChars(ccData[i]);
+ }
+ }
+
+ interface DisplayListener {
+ public void onDisplayChanged(SpannableStringBuilder[] styledTexts);
+ public CaptionStyle getCaptionStyle();
+ }
+
+ private CCMemory getMemory() {
+ // get the CC memory to operate on for current mode
+ switch (mMode) {
+ case MODE_POP_ON:
+ return mNonDisplay;
+ case MODE_TEXT:
+ // TODO(chz): support only caption mode for now,
+ // in text mode, dump everything to text mem.
+ return mTextMem;
+ case MODE_PAINT_ON:
+ case MODE_ROLL_UP:
+ return mDisplay;
+ default:
+ Log.w(TAG, "unrecoginized mode: " + mMode);
+ }
+ return mDisplay;
+ }
+
+ private boolean handleDisplayableChars(CCData ccData) {
+ if (!ccData.isDisplayableChar()) {
+ return false;
+ }
+
+ // Extended char includes 1 automatic backspace
+ if (ccData.isExtendedChar()) {
+ getMemory().bs();
+ }
+
+ getMemory().writeText(ccData.getDisplayText());
+
+ if (mMode == MODE_PAINT_ON || mMode == MODE_ROLL_UP) {
+ updateDisplay();
+ }
+
+ return true;
+ }
+
+ private boolean handleMidRowCode(CCData ccData) {
+ StyleCode m = ccData.getMidRow();
+ if (m != null) {
+ getMemory().writeMidRowCode(m);
+ return true;
+ }
+ return false;
+ }
+
+ private boolean handlePACCode(CCData ccData) {
+ PAC pac = ccData.getPAC();
+
+ if (pac != null) {
+ if (mMode == MODE_ROLL_UP) {
+ getMemory().moveBaselineTo(pac.getRow(), mRollUpSize);
+ }
+ getMemory().writePAC(pac);
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean handleTabOffsets(CCData ccData) {
+ int tabs = ccData.getTabOffset();
+
+ if (tabs > 0) {
+ getMemory().tab(tabs);
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean handleCtrlCode(CCData ccData) {
+ int ctrlCode = ccData.getCtrlCode();
+ switch(ctrlCode) {
+ case RCL:
+ // select pop-on style
+ mMode = MODE_POP_ON;
+ break;
+ case BS:
+ getMemory().bs();
+ break;
+ case DER:
+ getMemory().der();
+ break;
+ case RU2:
+ case RU3:
+ case RU4:
+ mRollUpSize = (ctrlCode - 0x23);
+ // erase memory if currently in other style
+ if (mMode != MODE_ROLL_UP) {
+ mDisplay.erase();
+ mNonDisplay.erase();
+ }
+ // select roll-up style
+ mMode = MODE_ROLL_UP;
+ break;
+ case FON:
+ Log.i(TAG, "Flash On");
+ break;
+ case RDC:
+ // select paint-on style
+ mMode = MODE_PAINT_ON;
+ break;
+ case TR:
+ mMode = MODE_TEXT;
+ mTextMem.erase();
+ break;
+ case RTD:
+ mMode = MODE_TEXT;
+ break;
+ case EDM:
+ // erase display memory
+ mDisplay.erase();
+ updateDisplay();
+ break;
+ case CR:
+ if (mMode == MODE_ROLL_UP) {
+ getMemory().rollUp(mRollUpSize);
+ } else {
+ getMemory().cr();
+ }
+ if (mMode == MODE_ROLL_UP) {
+ updateDisplay();
+ }
+ break;
+ case ENM:
+ // erase non-display memory
+ mNonDisplay.erase();
+ break;
+ case EOC:
+ // swap display/non-display memory
+ swapMemory();
+ // switch to pop-on style
+ mMode = MODE_POP_ON;
+ updateDisplay();
+ break;
+ case INVALID:
+ default:
+ // not handled
+ return false;
+ }
+
+ // handled
+ return true;
+ }
+
+ private void updateDisplay() {
+ if (mListener != null) {
+ CaptionStyle captionStyle = mListener.getCaptionStyle();
+ mListener.onDisplayChanged(mDisplay.getStyledText(captionStyle));
+ }
+ }
+
+ private void swapMemory() {
+ CCMemory temp = mDisplay;
+ mDisplay = mNonDisplay;
+ mNonDisplay = temp;
+ }
+
+ private static class StyleCode {
+ static final int COLOR_WHITE = 0;
+ static final int COLOR_GREEN = 1;
+ static final int COLOR_BLUE = 2;
+ static final int COLOR_CYAN = 3;
+ static final int COLOR_RED = 4;
+ static final int COLOR_YELLOW = 5;
+ static final int COLOR_MAGENTA = 6;
+ static final int COLOR_INVALID = 7;
+
+ static final int STYLE_ITALICS = 0x00000001;
+ static final int STYLE_UNDERLINE = 0x00000002;
+
+ static final String[] mColorMap = {
+ "WHITE", "GREEN", "BLUE", "CYAN", "RED", "YELLOW", "MAGENTA", "INVALID"
+ };
+
+ final int mStyle;
+ final int mColor;
+
+ static StyleCode fromByte(byte data2) {
+ int style = 0;
+ int color = (data2 >> 1) & 0x7;
+
+ if ((data2 & 0x1) != 0) {
+ style |= STYLE_UNDERLINE;
+ }
+
+ if (color == COLOR_INVALID) {
+ // WHITE ITALICS
+ color = COLOR_WHITE;
+ style |= STYLE_ITALICS;
+ }
+
+ return new StyleCode(style, color);
+ }
+
+ StyleCode(int style, int color) {
+ mStyle = style;
+ mColor = color;
+ }
+
+ boolean isItalics() {
+ return (mStyle & STYLE_ITALICS) != 0;
+ }
+
+ boolean isUnderline() {
+ return (mStyle & STYLE_UNDERLINE) != 0;
+ }
+
+ int getColor() {
+ return mColor;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder str = new StringBuilder();
+ str.append("{");
+ str.append(mColorMap[mColor]);
+ if ((mStyle & STYLE_ITALICS) != 0) {
+ str.append(", ITALICS");
+ }
+ if ((mStyle & STYLE_UNDERLINE) != 0) {
+ str.append(", UNDERLINE");
+ }
+ str.append("}");
+
+ return str.toString();
+ }
+ }
+
+ private static class PAC extends StyleCode {
+ final int mRow;
+ final int mCol;
+
+ static PAC fromBytes(byte data1, byte data2) {
+ int[] rowTable = {11, 1, 3, 12, 14, 5, 7, 9};
+ int row = rowTable[data1 & 0x07] + ((data2 & 0x20) >> 5);
+ int style = 0;
+ if ((data2 & 1) != 0) {
+ style |= STYLE_UNDERLINE;
+ }
+ if ((data2 & 0x10) != 0) {
+ // indent code
+ int indent = (data2 >> 1) & 0x7;
+ return new PAC(row, indent * 4, style, COLOR_WHITE);
+ } else {
+ // style code
+ int color = (data2 >> 1) & 0x7;
+
+ if (color == COLOR_INVALID) {
+ // WHITE ITALICS
+ color = COLOR_WHITE;
+ style |= STYLE_ITALICS;
+ }
+ return new PAC(row, -1, style, color);
+ }
+ }
+
+ PAC(int row, int col, int style, int color) {
+ super(style, color);
+ mRow = row;
+ mCol = col;
+ }
+
+ boolean isIndentPAC() {
+ return (mCol >= 0);
+ }
+
+ int getRow() {
+ return mRow;
+ }
+
+ int getCol() {
+ return mCol;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{%d, %d}, %s",
+ mRow, mCol, super.toString());
+ }
+ }
+
+ /* CCLineBuilder keeps track of displayable chars, as well as
+ * MidRow styles and PACs, for a single line of CC memory.
+ *
+ * It generates styled text via getStyledText() method.
+ */
+ private static class CCLineBuilder {
+ private final StringBuilder mDisplayChars;
+ private final StyleCode[] mMidRowStyles;
+ private final StyleCode[] mPACStyles;
+
+ CCLineBuilder(String str) {
+ mDisplayChars = new StringBuilder(str);
+ mMidRowStyles = new StyleCode[mDisplayChars.length()];
+ mPACStyles = new StyleCode[mDisplayChars.length()];
+ }
+
+ void setCharAt(int index, char ch) {
+ mDisplayChars.setCharAt(index, ch);
+ mMidRowStyles[index] = null;
+ }
+
+ void setMidRowAt(int index, StyleCode m) {
+ mDisplayChars.setCharAt(index, ' ');
+ mMidRowStyles[index] = m;
+ }
+
+ void setPACAt(int index, PAC pac) {
+ mPACStyles[index] = pac;
+ }
+
+ char charAt(int index) {
+ return mDisplayChars.charAt(index);
+ }
+
+ int length() {
+ return mDisplayChars.length();
+ }
+
+ void applyStyleSpan(
+ SpannableStringBuilder styledText,
+ StyleCode s, int start, int end) {
+ if (s.isItalics()) {
+ styledText.setSpan(
+ new StyleSpan(android.graphics.Typeface.ITALIC),
+ start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ if (s.isUnderline()) {
+ styledText.setSpan(
+ new UnderlineSpan(),
+ start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+
+ SpannableStringBuilder getStyledText(CaptionStyle captionStyle) {
+ SpannableStringBuilder styledText = new SpannableStringBuilder(mDisplayChars);
+ int start = -1, next = 0;
+ int styleStart = -1;
+ StyleCode curStyle = null;
+ while (next < mDisplayChars.length()) {
+ StyleCode newStyle = null;
+ if (mMidRowStyles[next] != null) {
+ // apply mid-row style change
+ newStyle = mMidRowStyles[next];
+ } else if (mPACStyles[next] != null
+ && (styleStart < 0 || start < 0)) {
+ // apply PAC style change, only if:
+ // 1. no style set, or
+ // 2. style set, but prev char is none-displayable
+ newStyle = mPACStyles[next];
+ }
+ if (newStyle != null) {
+ curStyle = newStyle;
+ if (styleStart >= 0 && start >= 0) {
+ applyStyleSpan(styledText, newStyle, styleStart, next);
+ }
+ styleStart = next;
+ }
+
+ if (mDisplayChars.charAt(next) != TS) {
+ if (start < 0) {
+ start = next;
+ }
+ } else if (start >= 0) {
+ int expandedStart = mDisplayChars.charAt(start) == ' ' ? start : start - 1;
+ int expandedEnd = mDisplayChars.charAt(next - 1) == ' ' ? next : next + 1;
+ styledText.setSpan(
+ new MutableBackgroundColorSpan(captionStyle.backgroundColor),
+ expandedStart, expandedEnd,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ if (styleStart >= 0) {
+ applyStyleSpan(styledText, curStyle, styleStart, expandedEnd);
+ }
+ start = -1;
+ }
+ next++;
+ }
+
+ return styledText;
+ }
+ }
+
+ /*
+ * CCMemory models a console-style display.
+ */
+ private static class CCMemory {
+ private final String mBlankLine;
+ private final CCLineBuilder[] mLines = new CCLineBuilder[MAX_ROWS + 2];
+ private int mRow;
+ private int mCol;
+
+ CCMemory() {
+ char[] blank = new char[MAX_COLS + 2];
+ Arrays.fill(blank, TS);
+ mBlankLine = new String(blank);
+ }
+
+ void erase() {
+ // erase all lines
+ for (int i = 0; i < mLines.length; i++) {
+ mLines[i] = null;
+ }
+ mRow = MAX_ROWS;
+ mCol = 1;
+ }
+
+ void der() {
+ if (mLines[mRow] != null) {
+ for (int i = 0; i < mCol; i++) {
+ if (mLines[mRow].charAt(i) != TS) {
+ for (int j = mCol; j < mLines[mRow].length(); j++) {
+ mLines[j].setCharAt(j, TS);
+ }
+ return;
+ }
+ }
+ mLines[mRow] = null;
+ }
+ }
+
+ void tab(int tabs) {
+ moveCursorByCol(tabs);
+ }
+
+ void bs() {
+ moveCursorByCol(-1);
+ if (mLines[mRow] != null) {
+ mLines[mRow].setCharAt(mCol, TS);
+ if (mCol == MAX_COLS - 1) {
+ // Spec recommendation:
+ // if cursor was at col 32, move cursor
+ // back to col 31 and erase both col 31&32
+ mLines[mRow].setCharAt(MAX_COLS, TS);
+ }
+ }
+ }
+
+ void cr() {
+ moveCursorTo(mRow + 1, 1);
+ }
+
+ void rollUp(int windowSize) {
+ int i;
+ for (i = 0; i <= mRow - windowSize; i++) {
+ mLines[i] = null;
+ }
+ int startRow = mRow - windowSize + 1;
+ if (startRow < 1) {
+ startRow = 1;
+ }
+ for (i = startRow; i < mRow; i++) {
+ mLines[i] = mLines[i + 1];
+ }
+ for (i = mRow; i < mLines.length; i++) {
+ // clear base row
+ mLines[i] = null;
+ }
+ // default to col 1, in case PAC is not sent
+ mCol = 1;
+ }
+
+ void writeText(String text) {
+ for (int i = 0; i < text.length(); i++) {
+ getLineBuffer(mRow).setCharAt(mCol, text.charAt(i));
+ moveCursorByCol(1);
+ }
+ }
+
+ void writeMidRowCode(StyleCode m) {
+ getLineBuffer(mRow).setMidRowAt(mCol, m);
+ moveCursorByCol(1);
+ }
+
+ void writePAC(PAC pac) {
+ if (pac.isIndentPAC()) {
+ moveCursorTo(pac.getRow(), pac.getCol());
+ } else {
+ moveCursorToRow(pac.getRow());
+ }
+ getLineBuffer(mRow).setPACAt(mCol, pac);
+ }
+
+ SpannableStringBuilder[] getStyledText(CaptionStyle captionStyle) {
+ ArrayList<SpannableStringBuilder> rows =
+ new ArrayList<SpannableStringBuilder>(MAX_ROWS);
+ for (int i = 1; i <= MAX_ROWS; i++) {
+ rows.add(mLines[i] != null ?
+ mLines[i].getStyledText(captionStyle) : null);
+ }
+ return rows.toArray(new SpannableStringBuilder[MAX_ROWS]);
+ }
+
+ private static int clamp(int x, int min, int max) {
+ return x < min ? min : (x > max ? max : x);
+ }
+
+ private void moveCursorTo(int row, int col) {
+ mRow = clamp(row, 1, MAX_ROWS);
+ mCol = clamp(col, 1, MAX_COLS);
+ }
+
+ private void moveCursorToRow(int row) {
+ mRow = clamp(row, 1, MAX_ROWS);
+ }
+
+ private void moveCursorByCol(int col) {
+ mCol = clamp(mCol + col, 1, MAX_COLS);
+ }
+
+ private void moveBaselineTo(int baseRow, int windowSize) {
+ if (mRow == baseRow) {
+ return;
+ }
+ int actualWindowSize = windowSize;
+ if (baseRow < actualWindowSize) {
+ actualWindowSize = baseRow;
+ }
+ if (mRow < actualWindowSize) {
+ actualWindowSize = mRow;
+ }
+
+ int i;
+ if (baseRow < mRow) {
+ // copy from bottom to top row
+ for (i = actualWindowSize - 1; i >= 0; i--) {
+ mLines[baseRow - i] = mLines[mRow - i];
+ }
+ } else {
+ // copy from top to bottom row
+ for (i = 0; i < actualWindowSize; i++) {
+ mLines[baseRow - i] = mLines[mRow - i];
+ }
+ }
+ // clear rest of the rows
+ for (i = 0; i <= baseRow - windowSize; i++) {
+ mLines[i] = null;
+ }
+ for (i = baseRow + 1; i < mLines.length; i++) {
+ mLines[i] = null;
+ }
+ }
+
+ private CCLineBuilder getLineBuffer(int row) {
+ if (mLines[row] == null) {
+ mLines[row] = new CCLineBuilder(mBlankLine);
+ }
+ return mLines[row];
+ }
+ }
+
+ /*
+ * CCData parses the raw CC byte pair into displayable chars,
+ * misc control codes, Mid-Row or Preamble Address Codes.
+ */
+ private static class CCData {
+ private final byte mType;
+ private final byte mData1;
+ private final byte mData2;
+
+ private static final String[] mCtrlCodeMap = {
+ "RCL", "BS" , "AOF", "AON",
+ "DER", "RU2", "RU3", "RU4",
+ "FON", "RDC", "TR" , "RTD",
+ "EDM", "CR" , "ENM", "EOC",
+ };
+
+ private static final String[] mSpecialCharMap = {
+ "\u00AE",
+ "\u00B0",
+ "\u00BD",
+ "\u00BF",
+ "\u2122",
+ "\u00A2",
+ "\u00A3",
+ "\u266A", // Eighth note
+ "\u00E0",
+ "\u00A0", // Transparent space
+ "\u00E8",
+ "\u00E2",
+ "\u00EA",
+ "\u00EE",
+ "\u00F4",
+ "\u00FB",
+ };
+
+ private static final String[] mSpanishCharMap = {
+ // Spanish and misc chars
+ "\u00C1", // A
+ "\u00C9", // E
+ "\u00D3", // I
+ "\u00DA", // O
+ "\u00DC", // U
+ "\u00FC", // u
+ "\u2018", // opening single quote
+ "\u00A1", // inverted exclamation mark
+ "*",
+ "'",
+ "\u2014", // em dash
+ "\u00A9", // Copyright
+ "\u2120", // Servicemark
+ "\u2022", // round bullet
+ "\u201C", // opening double quote
+ "\u201D", // closing double quote
+ // French
+ "\u00C0",
+ "\u00C2",
+ "\u00C7",
+ "\u00C8",
+ "\u00CA",
+ "\u00CB",
+ "\u00EB",
+ "\u00CE",
+ "\u00CF",
+ "\u00EF",
+ "\u00D4",
+ "\u00D9",
+ "\u00F9",
+ "\u00DB",
+ "\u00AB",
+ "\u00BB"
+ };
+
+ private static final String[] mProtugueseCharMap = {
+ // Portuguese
+ "\u00C3",
+ "\u00E3",
+ "\u00CD",
+ "\u00CC",
+ "\u00EC",
+ "\u00D2",
+ "\u00F2",
+ "\u00D5",
+ "\u00F5",
+ "{",
+ "}",
+ "\\",
+ "^",
+ "_",
+ "|",
+ "~",
+ // German and misc chars
+ "\u00C4",
+ "\u00E4",
+ "\u00D6",
+ "\u00F6",
+ "\u00DF",
+ "\u00A5",
+ "\u00A4",
+ "\u2502", // vertical bar
+ "\u00C5",
+ "\u00E5",
+ "\u00D8",
+ "\u00F8",
+ "\u250C", // top-left corner
+ "\u2510", // top-right corner
+ "\u2514", // lower-left corner
+ "\u2518", // lower-right corner
+ };
+
+ static CCData[] fromByteArray(byte[] data) {
+ CCData[] ccData = new CCData[data.length / 3];
+
+ for (int i = 0; i < ccData.length; i++) {
+ ccData[i] = new CCData(
+ data[i * 3],
+ data[i * 3 + 1],
+ data[i * 3 + 2]);
+ }
+
+ return ccData;
+ }
+
+ CCData(byte type, byte data1, byte data2) {
+ mType = type;
+ mData1 = data1;
+ mData2 = data2;
+ }
+
+ int getCtrlCode() {
+ if ((mData1 == 0x14 || mData1 == 0x1c)
+ && mData2 >= 0x20 && mData2 <= 0x2f) {
+ return mData2;
+ }
+ return INVALID;
+ }
+
+ StyleCode getMidRow() {
+ // only support standard Mid-row codes, ignore
+ // optional background/foreground mid-row codes
+ if ((mData1 == 0x11 || mData1 == 0x19)
+ && mData2 >= 0x20 && mData2 <= 0x2f) {
+ return StyleCode.fromByte(mData2);
+ }
+ return null;
+ }
+
+ PAC getPAC() {
+ if ((mData1 & 0x70) == 0x10
+ && (mData2 & 0x40) == 0x40
+ && ((mData1 & 0x07) != 0 || (mData2 & 0x20) == 0)) {
+ return PAC.fromBytes(mData1, mData2);
+ }
+ return null;
+ }
+
+ int getTabOffset() {
+ if ((mData1 == 0x17 || mData1 == 0x1f)
+ && mData2 >= 0x21 && mData2 <= 0x23) {
+ return mData2 & 0x3;
+ }
+ return 0;
+ }
+
+ boolean isDisplayableChar() {
+ return isBasicChar() || isSpecialChar() || isExtendedChar();
+ }
+
+ String getDisplayText() {
+ String str = getBasicChars();
+
+ if (str == null) {
+ str = getSpecialChar();
+
+ if (str == null) {
+ str = getExtendedChar();
+ }
+ }
+
+ return str;
+ }
+
+ private String ctrlCodeToString(int ctrlCode) {
+ return mCtrlCodeMap[ctrlCode - 0x20];
+ }
+
+ private boolean isBasicChar() {
+ return mData1 >= 0x20 && mData1 <= 0x7f;
+ }
+
+ private boolean isSpecialChar() {
+ return ((mData1 == 0x11 || mData1 == 0x19)
+ && mData2 >= 0x30 && mData2 <= 0x3f);
+ }
+
+ private boolean isExtendedChar() {
+ return ((mData1 == 0x12 || mData1 == 0x1A
+ || mData1 == 0x13 || mData1 == 0x1B)
+ && mData2 >= 0x20 && mData2 <= 0x3f);
+ }
+
+ private char getBasicChar(byte data) {
+ char c;
+ // replace the non-ASCII ones
+ switch (data) {
+ case 0x2A: c = '\u00E1'; break;
+ case 0x5C: c = '\u00E9'; break;
+ case 0x5E: c = '\u00ED'; break;
+ case 0x5F: c = '\u00F3'; break;
+ case 0x60: c = '\u00FA'; break;
+ case 0x7B: c = '\u00E7'; break;
+ case 0x7C: c = '\u00F7'; break;
+ case 0x7D: c = '\u00D1'; break;
+ case 0x7E: c = '\u00F1'; break;
+ case 0x7F: c = '\u2588'; break; // Full block
+ default: c = (char) data; break;
+ }
+ return c;
+ }
+
+ private String getBasicChars() {
+ if (mData1 >= 0x20 && mData1 <= 0x7f) {
+ StringBuilder builder = new StringBuilder(2);
+ builder.append(getBasicChar(mData1));
+ if (mData2 >= 0x20 && mData2 <= 0x7f) {
+ builder.append(getBasicChar(mData2));
+ }
+ return builder.toString();
+ }
+
+ return null;
+ }
+
+ private String getSpecialChar() {
+ if ((mData1 == 0x11 || mData1 == 0x19)
+ && mData2 >= 0x30 && mData2 <= 0x3f) {
+ return mSpecialCharMap[mData2 - 0x30];
+ }
+
+ return null;
+ }
+
+ private String getExtendedChar() {
+ if ((mData1 == 0x12 || mData1 == 0x1A)
+ && mData2 >= 0x20 && mData2 <= 0x3f){
+ // 1 Spanish/French char
+ return mSpanishCharMap[mData2 - 0x20];
+ } else if ((mData1 == 0x13 || mData1 == 0x1B)
+ && mData2 >= 0x20 && mData2 <= 0x3f){
+ // 1 Portuguese/German/Danish char
+ return mProtugueseCharMap[mData2 - 0x20];
+ }
+
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ String str;
+
+ if (mData1 < 0x10 && mData2 < 0x10) {
+ // Null Pad, ignore
+ return String.format("[%d]Null: %02x %02x", mType, mData1, mData2);
+ }
+
+ int ctrlCode = getCtrlCode();
+ if (ctrlCode != INVALID) {
+ return String.format("[%d]%s", mType, ctrlCodeToString(ctrlCode));
+ }
+
+ int tabOffset = getTabOffset();
+ if (tabOffset > 0) {
+ return String.format("[%d]Tab%d", mType, tabOffset);
+ }
+
+ PAC pac = getPAC();
+ if (pac != null) {
+ return String.format("[%d]PAC: %s", mType, pac.toString());
+ }
+
+ StyleCode m = getMidRow();
+ if (m != null) {
+ return String.format("[%d]Mid-row: %s", mType, m.toString());
+ }
+
+ if (isDisplayableChar()) {
+ return String.format("[%d]Displayable: %s (%02x %02x)",
+ mType, getDisplayText(), mData1, mData2);
+ }
+
+ return String.format("[%d]Invalid: %02x %02x", mType, mData1, mData2);
+ }
+ }
+}
+
+/**
+ * @hide
+ *
+ * MutableBackgroundColorSpan
+ *
+ * This is a mutable version of BackgroundSpan to facilitate text
+ * rendering with edge styles.
+ *
+ */
+class MutableBackgroundColorSpan extends CharacterStyle
+ implements UpdateAppearance, ParcelableSpan {
+ private int mColor;
+
+ public MutableBackgroundColorSpan(int color) {
+ mColor = color;
+ }
+ public MutableBackgroundColorSpan(Parcel src) {
+ mColor = src.readInt();
+ }
+ public void setBackgroundColor(int color) {
+ mColor = color;
+ }
+ public int getBackgroundColor() {
+ return mColor;
+ }
+ @Override
+ public int getSpanTypeId() {
+ return TextUtils.BACKGROUND_COLOR_SPAN;
+ }
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mColor);
+ }
+ @Override
+ public void updateDrawState(TextPaint ds) {
+ ds.bgColor = mColor;
+ }
+}
+
+/**
+ * Widget capable of rendering CEA-608 closed captions.
+ *
+ * @hide
+ */
+class ClosedCaptionWidget extends ViewGroup implements
+ SubtitleTrack.RenderingWidget,
+ CCParser.DisplayListener {
+ private static final String TAG = "ClosedCaptionWidget";
+
+ private static final Rect mTextBounds = new Rect();
+ private static final String mDummyText = "1234567890123456789012345678901234";
+ private static final CaptionStyle DEFAULT_CAPTION_STYLE = CaptionStyle.DEFAULT;
+
+ /** Captioning manager, used to obtain and track caption properties. */
+ private final CaptioningManager mManager;
+
+ /** Callback for rendering changes. */
+ private OnChangedListener mListener;
+
+ /** Current caption style. */
+ private CaptionStyle mCaptionStyle;
+
+ /* Closed caption layout. */
+ private CCLayout mClosedCaptionLayout;
+
+ /** Whether a caption style change listener is registered. */
+ private boolean mHasChangeListener;
+
+ public ClosedCaptionWidget(Context context) {
+ this(context, null);
+ }
+
+ public ClosedCaptionWidget(Context context, AttributeSet attrs) {
+ this(context, null, 0);
+ }
+
+ public ClosedCaptionWidget(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ // Cannot render text over video when layer type is hardware.
+ setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+
+ mManager = (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
+ mCaptionStyle = DEFAULT_CAPTION_STYLE.applyStyle(mManager.getUserStyle());
+
+ mClosedCaptionLayout = new CCLayout(context);
+ mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
+ addView(mClosedCaptionLayout, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+
+ requestLayout();
+ }
+
+ @Override
+ public void setOnChangedListener(OnChangedListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void setSize(int width, int height) {
+ final int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+ final int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
+ measure(widthSpec, heightSpec);
+ layout(0, 0, width, height);
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ if (visible) {
+ setVisibility(View.VISIBLE);
+ } else {
+ setVisibility(View.GONE);
+ }
+
+ manageChangeListener();
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ manageChangeListener();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ manageChangeListener();
+ }
+
+ @Override
+ public void onDisplayChanged(SpannableStringBuilder[] styledTexts) {
+ mClosedCaptionLayout.update(styledTexts);
+
+ if (mListener != null) {
+ mListener.onChanged(this);
+ }
+ }
+
+ @Override
+ public CaptionStyle getCaptionStyle() {
+ return mCaptionStyle;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ mClosedCaptionLayout.measure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ mClosedCaptionLayout.layout(l, t, r, b);
+ }
+
+ /**
+ * Manages whether this renderer is listening for caption style changes.
+ */
+ private final CaptioningChangeListener mCaptioningListener = new CaptioningChangeListener() {
+ @Override
+ public void onUserStyleChanged(CaptionStyle userStyle) {
+ mCaptionStyle = DEFAULT_CAPTION_STYLE.applyStyle(userStyle);
+ mClosedCaptionLayout.setCaptionStyle(mCaptionStyle);
+ }
+ };
+
+ private void manageChangeListener() {
+ final boolean needsListener = isAttachedToWindow() && getVisibility() == View.VISIBLE;
+ if (mHasChangeListener != needsListener) {
+ mHasChangeListener = needsListener;
+
+ if (needsListener) {
+ mManager.addCaptioningChangeListener(mCaptioningListener);
+ } else {
+ mManager.removeCaptioningChangeListener(mCaptioningListener);
+ }
+ }
+ }
+
+ private static class CCLineBox extends TextView {
+ private static final float FONT_PADDING_RATIO = 0.75f;
+ private static final float EDGE_OUTLINE_RATIO = 0.1f;
+ private static final float EDGE_SHADOW_RATIO = 0.05f;
+ private float mOutlineWidth;
+ private float mShadowRadius;
+ private float mShadowOffset;
+
+ private int mTextColor = Color.WHITE;
+ private int mBgColor = Color.BLACK;
+ private int mEdgeType = CaptionStyle.EDGE_TYPE_NONE;
+ private int mEdgeColor = Color.TRANSPARENT;
+
+ CCLineBox(Context context) {
+ super(context);
+ setGravity(Gravity.CENTER);
+ setBackgroundColor(Color.TRANSPARENT);
+ setTextColor(Color.WHITE);
+ setTypeface(Typeface.MONOSPACE);
+ setVisibility(View.INVISIBLE);
+
+ final Resources res = getContext().getResources();
+
+ // get the default (will be updated later during measure)
+ mOutlineWidth = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.subtitle_outline_width);
+ mShadowRadius = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.subtitle_shadow_radius);
+ mShadowOffset = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.subtitle_shadow_offset);
+ }
+
+ void setCaptionStyle(CaptionStyle captionStyle) {
+ mTextColor = captionStyle.foregroundColor;
+ mBgColor = captionStyle.backgroundColor;
+ mEdgeType = captionStyle.edgeType;
+ mEdgeColor = captionStyle.edgeColor;
+
+ setTextColor(mTextColor);
+ if (mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
+ setShadowLayer(mShadowRadius, mShadowOffset, mShadowOffset, mEdgeColor);
+ } else {
+ setShadowLayer(0, 0, 0, 0);
+ }
+ invalidate();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ float fontSize = MeasureSpec.getSize(heightMeasureSpec)
+ * FONT_PADDING_RATIO;
+ setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize);
+
+ mOutlineWidth = EDGE_OUTLINE_RATIO * fontSize + 1.0f;
+ mShadowRadius = EDGE_SHADOW_RATIO * fontSize + 1.0f;;
+ mShadowOffset = mShadowRadius;
+
+ // set font scale in the X direction to match the required width
+ setScaleX(1.0f);
+ getPaint().getTextBounds(mDummyText, 0, mDummyText.length(), mTextBounds);
+ float actualTextWidth = mTextBounds.width();
+ float requiredTextWidth = MeasureSpec.getSize(widthMeasureSpec);
+ setScaleX(requiredTextWidth / actualTextWidth);
+
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onDraw(Canvas c) {
+ if (mEdgeType == CaptionStyle.EDGE_TYPE_UNSPECIFIED
+ || mEdgeType == CaptionStyle.EDGE_TYPE_NONE
+ || mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
+ // these edge styles don't require a second pass
+ super.onDraw(c);
+ return;
+ }
+
+ if (mEdgeType == CaptionStyle.EDGE_TYPE_OUTLINE) {
+ drawEdgeOutline(c);
+ } else {
+ // Raised or depressed
+ drawEdgeRaisedOrDepressed(c);
+ }
+ }
+
+ private void drawEdgeOutline(Canvas c) {
+ TextPaint textPaint = getPaint();
+
+ Paint.Style previousStyle = textPaint.getStyle();
+ Paint.Join previousJoin = textPaint.getStrokeJoin();
+ float previousWidth = textPaint.getStrokeWidth();
+
+ setTextColor(mEdgeColor);
+ textPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ textPaint.setStrokeJoin(Paint.Join.ROUND);
+ textPaint.setStrokeWidth(mOutlineWidth);
+
+ // Draw outline and background only.
+ super.onDraw(c);
+
+ // Restore original settings.
+ setTextColor(mTextColor);
+ textPaint.setStyle(previousStyle);
+ textPaint.setStrokeJoin(previousJoin);
+ textPaint.setStrokeWidth(previousWidth);
+
+ // Remove the background.
+ setBackgroundSpans(Color.TRANSPARENT);
+ // Draw foreground only.
+ super.onDraw(c);
+ // Restore the background.
+ setBackgroundSpans(mBgColor);
+ }
+
+ private void drawEdgeRaisedOrDepressed(Canvas c) {
+ TextPaint textPaint = getPaint();
+
+ Paint.Style previousStyle = textPaint.getStyle();
+ textPaint.setStyle(Paint.Style.FILL);
+
+ final boolean raised = mEdgeType == CaptionStyle.EDGE_TYPE_RAISED;
+ final int colorUp = raised ? Color.WHITE : mEdgeColor;
+ final int colorDown = raised ? mEdgeColor : Color.WHITE;
+ final float offset = mShadowRadius / 2f;
+
+ // Draw background and text with shadow up
+ setShadowLayer(mShadowRadius, -offset, -offset, colorUp);
+ super.onDraw(c);
+
+ // Remove the background.
+ setBackgroundSpans(Color.TRANSPARENT);
+
+ // Draw text with shadow down
+ setShadowLayer(mShadowRadius, +offset, +offset, colorDown);
+ super.onDraw(c);
+
+ // Restore settings
+ textPaint.setStyle(previousStyle);
+
+ // Restore the background.
+ setBackgroundSpans(mBgColor);
+ }
+
+ private void setBackgroundSpans(int color) {
+ CharSequence text = getText();
+ if (text instanceof Spannable) {
+ Spannable spannable = (Spannable) text;
+ MutableBackgroundColorSpan[] bgSpans = spannable.getSpans(
+ 0, spannable.length(), MutableBackgroundColorSpan.class);
+ for (int i = 0; i < bgSpans.length; i++) {
+ bgSpans[i].setBackgroundColor(color);
+ }
+ }
+ }
+ }
+
+ private static class CCLayout extends LinearLayout {
+ private static final int MAX_ROWS = CCParser.MAX_ROWS;
+ private static final float SAFE_AREA_RATIO = 0.9f;
+
+ private final CCLineBox[] mLineBoxes = new CCLineBox[MAX_ROWS];
+
+ CCLayout(Context context) {
+ super(context);
+ setGravity(Gravity.START);
+ setOrientation(LinearLayout.VERTICAL);
+ for (int i = 0; i < MAX_ROWS; i++) {
+ mLineBoxes[i] = new CCLineBox(getContext());
+ addView(mLineBoxes[i], LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ }
+ }
+
+ void setCaptionStyle(CaptionStyle captionStyle) {
+ for (int i = 0; i < MAX_ROWS; i++) {
+ mLineBoxes[i].setCaptionStyle(captionStyle);
+ }
+ }
+
+ void update(SpannableStringBuilder[] textBuffer) {
+ for (int i = 0; i < MAX_ROWS; i++) {
+ if (textBuffer[i] != null) {
+ mLineBoxes[i].setText(textBuffer[i], TextView.BufferType.SPANNABLE);
+ mLineBoxes[i].setVisibility(View.VISIBLE);
+ } else {
+ mLineBoxes[i].setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ int safeWidth = getMeasuredWidth();
+ int safeHeight = getMeasuredHeight();
+
+ // CEA-608 assumes 4:3 video
+ if (safeWidth * 3 >= safeHeight * 4) {
+ safeWidth = safeHeight * 4 / 3;
+ } else {
+ safeHeight = safeWidth * 3 / 4;
+ }
+ safeWidth *= SAFE_AREA_RATIO;
+ safeHeight *= SAFE_AREA_RATIO;
+
+ int lineHeight = safeHeight / MAX_ROWS;
+ int lineHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+ lineHeight, MeasureSpec.EXACTLY);
+ int lineWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+ safeWidth, MeasureSpec.EXACTLY);
+
+ for (int i = 0; i < MAX_ROWS; i++) {
+ mLineBoxes[i].measure(lineWidthMeasureSpec, lineHeightMeasureSpec);
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ // safe caption area
+ int viewPortWidth = r - l;
+ int viewPortHeight = b - t;
+ int safeWidth, safeHeight;
+ // CEA-608 assumes 4:3 video
+ if (viewPortWidth * 3 >= viewPortHeight * 4) {
+ safeWidth = viewPortHeight * 4 / 3;
+ safeHeight = viewPortHeight;
+ } else {
+ safeWidth = viewPortWidth;
+ safeHeight = viewPortWidth * 3 / 4;
+ }
+ safeWidth *= SAFE_AREA_RATIO;
+ safeHeight *= SAFE_AREA_RATIO;
+ int left = (viewPortWidth - safeWidth) / 2;
+ int top = (viewPortHeight - safeHeight) / 2;
+
+ for (int i = 0; i < MAX_ROWS; i++) {
+ mLineBoxes[i].layout(
+ left,
+ top + safeHeight * i / MAX_ROWS,
+ left + safeWidth,
+ top + safeHeight * (i + 1) / MAX_ROWS);
+ }
+ }
+ }
+};
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index e59623b..c29e967 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -62,7 +62,7 @@
boolean isStreamMute(int streamType);
- void setMasterMute(boolean state, int flags, IBinder cb);
+ void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb);
boolean isMasterMute();
@@ -78,6 +78,8 @@
int getLastAudibleMasterVolume();
+ void setMicrophoneMute(boolean on, String callingPackage);
+
void setRingerMode(int ringerMode);
int getRingerMode();
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index f258063..22db344 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -782,7 +782,7 @@
private void postEventFromNative(
int what, int arg1, int arg2, Object obj) {
- if (mEventHandler != null) {
+ if (mEventHandler != null && mNotificationCallback != null) {
Message msg = mEventHandler.obtainMessage(what, arg1, arg2, obj);
mEventHandler.sendMessage(msg);
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 1b92410..e25714a 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1649,8 +1649,8 @@
mFormat = MediaFormat.createSubtitleFormat(
MEDIA_MIMETYPE_TEXT_SUBRIP, language);
} else if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- mFormat = MediaFormat.createSubtitleFormat(
- MEDIA_MIMETYPE_TEXT_VTT, language);
+ String mime = in.readString();
+ mFormat = MediaFormat.createSubtitleFormat(mime, language);
mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.readInt());
mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.readInt());
mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.readInt());
@@ -1683,12 +1683,40 @@
dest.writeString(getLanguage());
if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
+ dest.writeString(mFormat.getString(MediaFormat.KEY_MIME));
dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT));
dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT));
dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE));
}
}
+ @Override
+ public String toString() {
+ StringBuilder out = new StringBuilder(128);
+ out.append(getClass().getName());
+ out.append('{');
+ switch (mTrackType) {
+ case MEDIA_TRACK_TYPE_VIDEO:
+ out.append("VIDEO");
+ break;
+ case MEDIA_TRACK_TYPE_AUDIO:
+ out.append("AUDIO");
+ break;
+ case MEDIA_TRACK_TYPE_TIMEDTEXT:
+ out.append("TIMEDTEXT");
+ break;
+ case MEDIA_TRACK_TYPE_SUBTITLE:
+ out.append("SUBTITLE");
+ break;
+ default:
+ out.append("UNKNOWN");
+ break;
+ }
+ out.append(", " + mFormat.toString());
+ out.append("}");
+ return out.toString();
+ }
+
/**
* Used to read a TrackInfo from a Parcel.
*/
@@ -1757,6 +1785,12 @@
*/
public static final String MEDIA_MIMETYPE_TEXT_VTT = "text/vtt";
+ /**
+ * MIME type for CEA-608 closed caption data.
+ * @hide
+ */
+ public static final String MEDIA_MIMETYPE_TEXT_CEA_608 = "text/cea-608";
+
/*
* A helper function to check if the mime type is supported by media framework.
*/
@@ -1792,16 +1826,11 @@
}
SubtitleTrack track = mInbandSubtitleTracks[index];
if (track != null) {
- try {
- long runID = data.getStartTimeUs() + 1;
- // TODO: move conversion into track
- track.onData(new String(data.getData(), "UTF-8"), true /* eos */, runID);
- track.setRunDiscardTimeMs(
- runID,
- (data.getStartTimeUs() + data.getDurationUs()) / 1000);
- } catch (java.io.UnsupportedEncodingException e) {
- Log.w(TAG, "subtitle data for track " + index + " is not UTF-8 encoded: " + e);
- }
+ long runID = data.getStartTimeUs() + 1;
+ track.onData(data.getData(), true /* eos */, runID);
+ track.setRunDiscardTimeMs(
+ runID,
+ (data.getStartTimeUs() + data.getDurationUs()) / 1000);
}
}
};
@@ -1872,7 +1901,7 @@
}
scanner.close();
mOutOfBandSubtitleTracks.add(track);
- track.onData(contents, true /* eos */, ~0 /* runID: keep forever */);
+ track.onData(contents.getBytes(), true /* eos */, ~0 /* runID: keep forever */);
return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
}
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index a4d491d8..ddd5b72 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -28,6 +28,8 @@
import android.hardware.display.DisplayManager;
import android.hardware.display.WifiDisplay;
import android.hardware.display.WifiDisplayStatus;
+import android.media.session.MediaSession;
+import android.media.session.RemoteVolumeProvider;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
@@ -1141,7 +1143,7 @@
public RouteCategory createRouteCategory(CharSequence name, boolean isGroupable) {
return new RouteCategory(name, ROUTE_TYPE_USER, isGroupable);
}
-
+
/**
* Create a new route category. Each route must belong to a category.
*
@@ -1980,6 +1982,7 @@
*/
public static class UserRouteInfo extends RouteInfo {
RemoteControlClient mRcc;
+ SessionVolumeProvider mSvp;
UserRouteInfo(RouteCategory category) {
super(category);
@@ -1996,7 +1999,7 @@
mName = name;
routeUpdated();
}
-
+
/**
* Set the user-visible name of this route.
* <p>
@@ -2100,7 +2103,7 @@
public void setPlaybackType(int type) {
if (mPlaybackType != type) {
mPlaybackType = type;
- setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, type);
+ configureSessionVolume();
}
}
@@ -2113,8 +2116,7 @@
public void setVolumeHandling(int volumeHandling) {
if (mVolumeHandling != volumeHandling) {
mVolumeHandling = volumeHandling;
- setPlaybackInfoOnRcc(
- RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, volumeHandling);
+ configureSessionVolume();
}
}
@@ -2127,7 +2129,9 @@
volume = Math.max(0, Math.min(volume, getVolumeMax()));
if (mVolume != volume) {
mVolume = volume;
- setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME, volume);
+ if (mSvp != null) {
+ mSvp.notifyVolumeChanged();
+ }
dispatchRouteVolumeChanged(this);
if (mGroup != null) {
mGroup.memberVolumeChanged(this);
@@ -2166,7 +2170,7 @@
public void setVolumeMax(int volumeMax) {
if (mVolumeMax != volumeMax) {
mVolumeMax = volumeMax;
- setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, volumeMax);
+ configureSessionVolume();
}
}
@@ -2177,35 +2181,84 @@
public void setPlaybackStream(int stream) {
if (mPlaybackStream != stream) {
mPlaybackStream = stream;
- setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_USES_STREAM, stream);
+ configureSessionVolume();
}
}
private void updatePlaybackInfoOnRcc() {
- if ((mRcc != null) && (mRcc.getRcseId() != RemoteControlClient.RCSE_ID_UNREGISTERED)) {
- mRcc.setPlaybackInformation(
- RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, mVolumeMax);
- mRcc.setPlaybackInformation(
- RemoteControlClient.PLAYBACKINFO_VOLUME, mVolume);
- mRcc.setPlaybackInformation(
- RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, mVolumeHandling);
- mRcc.setPlaybackInformation(
- RemoteControlClient.PLAYBACKINFO_USES_STREAM, mPlaybackStream);
- mRcc.setPlaybackInformation(
- RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, mPlaybackType);
- // let AudioService know whom to call when remote volume needs to be updated
- try {
- sStatic.mAudioService.registerRemoteVolumeObserverForRcc(
- mRcc.getRcseId() /* rccId */, mRemoteVolObserver /* rvo */);
- } catch (RemoteException e) {
- Log.e(TAG, "Error registering remote volume observer", e);
+ configureSessionVolume();
+ }
+
+ private void configureSessionVolume() {
+ if (mRcc == null) {
+ if (DEBUG) {
+ Log.d(TAG, "No Rcc to configure volume for route " + mName);
}
+ return;
+ }
+ MediaSession session = mRcc.getMediaSession();
+ if (session == null) {
+ if (DEBUG) {
+ Log.d(TAG, "Rcc has no session to configure volume");
+ }
+ return;
+ }
+ if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) {
+ int volumeControl = RemoteVolumeProvider.VOLUME_CONTROL_FIXED;
+ switch (mVolumeHandling) {
+ case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE:
+ volumeControl = RemoteVolumeProvider.VOLUME_CONTROL_ABSOLUTE;
+ break;
+ case RemoteControlClient.PLAYBACK_VOLUME_FIXED:
+ default:
+ break;
+ }
+ // Only register a new listener if necessary
+ if (mSvp == null || mSvp.getVolumeControl() != volumeControl
+ || mSvp.getMaxVolume() != mVolumeMax) {
+ mSvp = new SessionVolumeProvider(volumeControl, mVolumeMax);
+ session.setPlaybackToRemote(mSvp);
+ }
+ } else {
+ // We only know how to handle local and remote, fall back to local if not remote.
+ session.setPlaybackToLocal(mPlaybackStream);
+ mSvp = null;
}
}
- private void setPlaybackInfoOnRcc(int what, int value) {
- if (mRcc != null) {
- mRcc.setPlaybackInformation(what, value);
+ class SessionVolumeProvider extends RemoteVolumeProvider {
+
+ public SessionVolumeProvider(int volumeControl, int maxVolume) {
+ super(volumeControl, maxVolume);
+ }
+
+ @Override
+ public int onGetCurrentVolume() {
+ return mVcb == null ? 0 : mVcb.route.mVolume;
+ }
+
+ @Override
+ public void onSetVolumeTo(final int volume) {
+ sStatic.mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mVcb != null) {
+ mVcb.vcb.onVolumeSetRequest(mVcb.route, volume);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onAdjustVolumeBy(final int delta) {
+ sStatic.mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mVcb != null) {
+ mVcb.vcb.onVolumeUpdateRequest(mVcb.route, delta);
+ }
+ }
+ });
}
}
}
@@ -2504,17 +2557,17 @@
public CharSequence getName() {
return getName(sStatic.mResources);
}
-
+
/**
* Return the properly localized/configuration dependent name of this RouteCategory.
- *
+ *
* @param context Context to resolve name resources
* @return the name of this route category
*/
public CharSequence getName(Context context) {
return getName(context.getResources());
}
-
+
CharSequence getName(Resources res) {
if (mNameResId != 0) {
return res.getText(mNameResId);
diff --git a/media/java/android/media/PlayerRecord.java b/media/java/android/media/PlayerRecord.java
index f9708c3..664ddcf 100644
--- a/media/java/android/media/PlayerRecord.java
+++ b/media/java/android/media/PlayerRecord.java
@@ -56,7 +56,7 @@
*/
final private ComponentName mReceiverComponent;
- private int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+ private int mRccId = -1;
/**
* A non-null token implies this record tracks a "live" player whose death is being monitored.
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 0caea5f..73bc61a 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -561,6 +561,8 @@
return;
}
synchronized (mCacheLock) {
+ // Still build the old metadata so when creating a new editor
+ // you get the expected values.
// assign the edited data
mMetadata = new Bundle(mEditorMetadata);
// add the information about editable keys
@@ -570,16 +572,6 @@
}
mOriginalArtwork = mEditorArtwork;
mEditorArtwork = null;
- if (mMetadataChanged & mArtworkChanged) {
- // send to remote control display if conditions are met
- sendMetadataWithArtwork_syncCacheLock(null, 0, 0);
- } else if (mMetadataChanged) {
- // send to remote control display if conditions are met
- sendMetadata_syncCacheLock(null);
- } else if (mArtworkChanged) {
- // send to remote control display if conditions are met
- sendArtwork_syncCacheLock(null, 0, 0);
- }
// USE_SESSIONS
if (mSession != null && mMetadataBuilder != null) {
@@ -687,14 +679,6 @@
// keep track of when the state change occurred
mPlaybackStateChangeTimeMs = SystemClock.elapsedRealtime();
- // send to remote control display if conditions are met
- sendPlaybackState_syncCacheLock(null);
- // update AudioService
- sendAudioServiceNewPlaybackState_syncCacheLock();
-
- // handle automatic playback position refreshes
- initiateCheckForDrift_syncCacheLock();
-
// USE_SESSIONS
if (mSession != null) {
int pbState = PlaybackState.getStateFromRccState(state);
@@ -707,29 +691,7 @@
}
}
- private void initiateCheckForDrift_syncCacheLock() {
- if (mEventHandler == null) {
- return;
- }
- mEventHandler.removeMessages(MSG_POSITION_DRIFT_CHECK);
- if (!mNeedsPositionSync) {
- return;
- }
- if (mPlaybackPositionMs < 0) {
- // the current playback state has no known playback position, it's no use
- // trying to see if there is any drift at this point
- // (this also bypasses this mechanism for older apps that use the old
- // setPlaybackState(int) API)
- return;
- }
- if (playbackPositionShouldMove(mPlaybackState)) {
- // playback position moving, schedule next position drift check
- mEventHandler.sendMessageDelayed(
- mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
- getCheckPeriodFromSpeed(mPlaybackSpeed));
- }
- }
-
+ // TODO investigate if we still need position drift checking
private void onPositionDriftCheck() {
if (DEBUG) { Log.d(TAG, "onPositionDriftCheck()"); }
synchronized(mCacheLock) {
@@ -781,9 +743,6 @@
// store locally
mTransportControlFlags = transportControlFlags;
- // send to remote control display if conditions are met
- sendTransportControlInfo_syncCacheLock(null);
-
// USE_SESSIONS
if (mSession != null) {
mSessionPlaybackState.setActions(PlaybackState
@@ -866,17 +825,7 @@
*/
public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener l) {
synchronized(mCacheLock) {
- int oldCapa = mPlaybackPositionCapabilities;
- if (l != null) {
- mPlaybackPositionCapabilities |= MEDIA_POSITION_WRITABLE;
- } else {
- mPlaybackPositionCapabilities &= ~MEDIA_POSITION_WRITABLE;
- }
mPositionUpdateListener = l;
- if (oldCapa != mPlaybackPositionCapabilities) {
- // tell RCDs that this RCC's playback position capabilities have changed
- sendTransportControlInfo_syncCacheLock(null);
- }
}
}
@@ -888,17 +837,7 @@
*/
public void setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener l) {
synchronized(mCacheLock) {
- int oldCapa = mPlaybackPositionCapabilities;
- if (l != null) {
- mPlaybackPositionCapabilities |= MEDIA_POSITION_READABLE;
- } else {
- mPlaybackPositionCapabilities &= ~MEDIA_POSITION_READABLE;
- }
mPositionProvider = l;
- if (oldCapa != mPlaybackPositionCapabilities) {
- // tell RCDs that this RCC's playback position capabilities have changed
- sendTransportControlInfo_syncCacheLock(null);
- }
if ((mPositionProvider != null) && (mEventHandler != null)
&& playbackPositionShouldMove(mPlaybackState)) {
// playback position is already moving, but now we have a position provider,
@@ -925,124 +864,12 @@
*/
public static int MEDIA_POSITION_WRITABLE = 1 << 1;
- private int mPlaybackPositionCapabilities = 0;
-
/** @hide */
public final static int DEFAULT_PLAYBACK_VOLUME_HANDLING = PLAYBACK_VOLUME_VARIABLE;
/** @hide */
// hard-coded to the same number of steps as AudioService.MAX_STREAM_VOLUME[STREAM_MUSIC]
public final static int DEFAULT_PLAYBACK_VOLUME = 15;
- private int mPlaybackType = PLAYBACK_TYPE_LOCAL;
- private int mPlaybackVolumeMax = DEFAULT_PLAYBACK_VOLUME;
- private int mPlaybackVolume = DEFAULT_PLAYBACK_VOLUME;
- private int mPlaybackVolumeHandling = DEFAULT_PLAYBACK_VOLUME_HANDLING;
- private int mPlaybackStream = AudioManager.STREAM_MUSIC;
-
- /**
- * @hide
- * Set information describing information related to the playback of media so the system
- * can implement additional behavior to handle non-local playback usecases.
- * @param what a key to specify the type of information to set. Valid keys are
- * {@link #PLAYBACKINFO_PLAYBACK_TYPE},
- * {@link #PLAYBACKINFO_USES_STREAM},
- * {@link #PLAYBACKINFO_VOLUME},
- * {@link #PLAYBACKINFO_VOLUME_MAX},
- * and {@link #PLAYBACKINFO_VOLUME_HANDLING}.
- * @param value the value for the supplied information to set.
- */
- public void setPlaybackInformation(int what, int value) {
- synchronized(mCacheLock) {
- switch (what) {
- case PLAYBACKINFO_PLAYBACK_TYPE:
- if ((value >= PLAYBACK_TYPE_MIN) && (value <= PLAYBACK_TYPE_MAX)) {
- if (mPlaybackType != value) {
- mPlaybackType = value;
- sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
- }
- } else {
- Log.w(TAG, "using invalid value for PLAYBACKINFO_PLAYBACK_TYPE");
- }
- break;
- case PLAYBACKINFO_VOLUME:
- if ((value > -1) && (value <= mPlaybackVolumeMax)) {
- if (mPlaybackVolume != value) {
- mPlaybackVolume = value;
- sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
- }
- } else {
- Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME");
- }
- break;
- case PLAYBACKINFO_VOLUME_MAX:
- if (value > 0) {
- if (mPlaybackVolumeMax != value) {
- mPlaybackVolumeMax = value;
- sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
- }
- } else {
- Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME_MAX");
- }
- break;
- case PLAYBACKINFO_USES_STREAM:
- if ((value >= 0) && (value < AudioSystem.getNumStreamTypes())) {
- mPlaybackStream = value;
- } else {
- Log.w(TAG, "using invalid value for PLAYBACKINFO_USES_STREAM");
- }
- break;
- case PLAYBACKINFO_VOLUME_HANDLING:
- if ((value >= PLAYBACK_VOLUME_FIXED) && (value <= PLAYBACK_VOLUME_VARIABLE)) {
- if (mPlaybackVolumeHandling != value) {
- mPlaybackVolumeHandling = value;
- sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
- }
- } else {
- Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME_HANDLING");
- }
- break;
- default:
- // not throwing an exception or returning an error if more keys are to be
- // supported in the future
- Log.w(TAG, "setPlaybackInformation() ignoring unknown key " + what);
- break;
- }
- }
- }
-
- /**
- * @hide
- * Return playback information represented as an integer value.
- * @param what a key to specify the type of information to retrieve. Valid keys are
- * {@link #PLAYBACKINFO_PLAYBACK_TYPE},
- * {@link #PLAYBACKINFO_USES_STREAM},
- * {@link #PLAYBACKINFO_VOLUME},
- * {@link #PLAYBACKINFO_VOLUME_MAX},
- * and {@link #PLAYBACKINFO_VOLUME_HANDLING}.
- * @return the current value for the given information type, or
- * {@link #PLAYBACKINFO_INVALID_VALUE} if an error occurred or the request is invalid, or
- * the value is unknown.
- */
- public int getIntPlaybackInformation(int what) {
- synchronized(mCacheLock) {
- switch (what) {
- case PLAYBACKINFO_PLAYBACK_TYPE:
- return mPlaybackType;
- case PLAYBACKINFO_VOLUME:
- return mPlaybackVolume;
- case PLAYBACKINFO_VOLUME_MAX:
- return mPlaybackVolumeMax;
- case PLAYBACKINFO_USES_STREAM:
- return mPlaybackStream;
- case PLAYBACKINFO_VOLUME_HANDLING:
- return mPlaybackVolumeHandling;
- default:
- Log.e(TAG, "getIntPlaybackInformation() unknown key " + what);
- return PLAYBACKINFO_INVALID_VALUE;
- }
- }
- }
-
/**
* Lock for all cached data
*/
@@ -1102,13 +929,6 @@
* The current remote control client generation ID across the system, as known by this object
*/
private int mCurrentClientGenId = -1;
- /**
- * The remote control client generation ID, the last time it was told it was the current RC.
- * If (mCurrentClientGenId == mInternalClientGenId) is true, it means that this remote control
- * client is the "focused" one, and that whenever this client's info is updated, it needs to
- * send it to the known IRemoteControlDisplay interfaces.
- */
- private int mInternalClientGenId = -2;
/**
* The media button intent description associated with this remote control client
@@ -1134,186 +954,18 @@
private MediaMetadata mMediaMetadata;
/**
- * A class to encapsulate all the information about a remote control display.
- * A RemoteControlClient's metadata and state may be displayed on multiple IRemoteControlDisplay
- */
- private class DisplayInfoForClient {
- /** may never be null */
- private IRemoteControlDisplay mRcDisplay;
- private int mArtworkExpectedWidth;
- private int mArtworkExpectedHeight;
- private boolean mWantsPositionSync = false;
- private boolean mEnabled = true;
-
- DisplayInfoForClient(IRemoteControlDisplay rcd, int w, int h) {
- mRcDisplay = rcd;
- mArtworkExpectedWidth = w;
- mArtworkExpectedHeight = h;
- }
- }
-
- /**
- * The list of remote control displays to which this client will send information.
- * Accessed and modified synchronized on mCacheLock
- */
- private ArrayList<DisplayInfoForClient> mRcDisplays = new ArrayList<DisplayInfoForClient>(1);
-
- /**
* @hide
* Accessor to media button intent description (includes target component)
*/
public PendingIntent getRcMediaIntent() {
return mRcMediaIntent;
}
- /**
- * @hide
- * Accessor to IRemoteControlClient
- */
- public IRemoteControlClient getIRemoteControlClient() {
- return mIRCC;
- }
-
- /**
- * The IRemoteControlClient implementation
- */
- private final IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() {
-
- //TODO change name to informationRequestForAllDisplays()
- public void onInformationRequested(int generationId, int infoFlags) {
- // only post messages, we can't block here
- if (mEventHandler != null) {
- // signal new client
- mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN);
- mEventHandler.sendMessage(
- mEventHandler.obtainMessage(MSG_NEW_INTERNAL_CLIENT_GEN,
- /*arg1*/ generationId, /*arg2, ignored*/ 0));
- // send the information
- mEventHandler.removeMessages(MSG_REQUEST_PLAYBACK_STATE);
- mEventHandler.removeMessages(MSG_REQUEST_METADATA);
- mEventHandler.removeMessages(MSG_REQUEST_TRANSPORTCONTROL);
- mEventHandler.removeMessages(MSG_REQUEST_ARTWORK);
- mEventHandler.removeMessages(MSG_REQUEST_METADATA_ARTWORK);
- mEventHandler.sendMessage(
- mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE, null));
- mEventHandler.sendMessage(
- mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL, null));
- mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA_ARTWORK,
- 0, 0, null));
- }
- }
-
- public void informationRequestForDisplay(IRemoteControlDisplay rcd, int w, int h) {
- // only post messages, we can't block here
- if (mEventHandler != null) {
- mEventHandler.sendMessage(
- mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL, rcd));
- mEventHandler.sendMessage(
- mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE, rcd));
- if ((w > 0) && (h > 0)) {
- mEventHandler.sendMessage(
- mEventHandler.obtainMessage(MSG_REQUEST_METADATA_ARTWORK, w, h, rcd));
- } else {
- mEventHandler.sendMessage(
- mEventHandler.obtainMessage(MSG_REQUEST_METADATA, rcd));
- }
- }
- }
-
- public void setCurrentClientGenerationId(int clientGeneration) {
- // only post messages, we can't block here
- if (mEventHandler != null) {
- mEventHandler.removeMessages(MSG_NEW_CURRENT_CLIENT_GEN);
- mEventHandler.sendMessage(mEventHandler.obtainMessage(
- MSG_NEW_CURRENT_CLIENT_GEN, clientGeneration, 0/*ignored*/));
- }
- }
-
- public void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
- // only post messages, we can't block here
- if ((mEventHandler != null) && (rcd != null)) {
- mEventHandler.sendMessage(mEventHandler.obtainMessage(
- MSG_PLUG_DISPLAY, w, h, rcd));
- }
- }
-
- public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) {
- // only post messages, we can't block here
- if ((mEventHandler != null) && (rcd != null)) {
- mEventHandler.sendMessage(mEventHandler.obtainMessage(
- MSG_UNPLUG_DISPLAY, rcd));
- }
- }
-
- public void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h) {
- // only post messages, we can't block here
- if ((mEventHandler != null) && (rcd != null)) {
- mEventHandler.sendMessage(mEventHandler.obtainMessage(
- MSG_UPDATE_DISPLAY_ARTWORK_SIZE, w, h, rcd));
- }
- }
-
- public void setWantsSyncForDisplay(IRemoteControlDisplay rcd, boolean wantsSync) {
- // only post messages, we can't block here
- if ((mEventHandler != null) && (rcd != null)) {
- mEventHandler.sendMessage(mEventHandler.obtainMessage(
- MSG_DISPLAY_WANTS_POS_SYNC, wantsSync ? 1 : 0, 0/*arg2 ignored*/, rcd));
- }
- }
-
- public void enableRemoteControlDisplay(IRemoteControlDisplay rcd, boolean enabled) {
- // only post messages, we can't block here
- if ((mEventHandler != null) && (rcd != null)) {
- mEventHandler.sendMessage(mEventHandler.obtainMessage(
- MSG_DISPLAY_ENABLE, enabled ? 1 : 0, 0/*arg2 ignored*/, rcd));
- }
- }
-
- public void seekTo(int generationId, long timeMs) {
- // only post messages, we can't block here
- if (mEventHandler != null) {
- mEventHandler.removeMessages(MSG_SEEK_TO);
- mEventHandler.sendMessage(mEventHandler.obtainMessage(
- MSG_SEEK_TO, generationId /* arg1 */, 0 /* arg2, ignored */,
- new Long(timeMs)));
- }
- }
-
- public void updateMetadata(int generationId, int key, Rating value) {
- // only post messages, we can't block here
- if (mEventHandler != null) {
- mEventHandler.sendMessage(mEventHandler.obtainMessage(
- MSG_UPDATE_METADATA, generationId /* arg1 */, key /* arg2*/, value));
- }
- }
- };
/**
* @hide
* Default value for the unique identifier
*/
public final static int RCSE_ID_UNREGISTERED = -1;
- /**
- * Unique identifier of the RemoteControlStackEntry in AudioService with which
- * this RemoteControlClient is associated.
- */
- private int mRcseId = RCSE_ID_UNREGISTERED;
- /**
- * @hide
- * To be only used by AudioManager after it has received the unique id from
- * IAudioService.registerRemoteControlClient()
- * @param id the unique identifier of the RemoteControlStackEntry in AudioService with which
- * this RemoteControlClient is associated.
- */
- public void setRcseId(int id) {
- mRcseId = id;
- }
-
- /**
- * @hide
- */
- public int getRcseId() {
- return mRcseId;
- }
// USE_SESSIONS
private MediaSession.TransportControlsCallback mTransportListener
@@ -1327,31 +979,13 @@
@Override
public void onSetRating(Rating rating) {
if ((mTransportControlFlags & FLAG_KEY_MEDIA_RATING) != 0) {
- if (mEventHandler != null) {
- mEventHandler.sendMessage(mEventHandler.obtainMessage(
- MSG_UPDATE_METADATA, mCurrentClientGenId,
- MetadataEditor.RATING_KEY_BY_USER, rating));
- }
+ onUpdateMetadata(mCurrentClientGenId, MetadataEditor.RATING_KEY_BY_USER, rating);
}
}
};
private EventHandler mEventHandler;
- private final static int MSG_REQUEST_PLAYBACK_STATE = 1;
- private final static int MSG_REQUEST_METADATA = 2;
- private final static int MSG_REQUEST_TRANSPORTCONTROL = 3;
- private final static int MSG_REQUEST_ARTWORK = 4;
- private final static int MSG_NEW_INTERNAL_CLIENT_GEN = 5;
- private final static int MSG_NEW_CURRENT_CLIENT_GEN = 6;
- private final static int MSG_PLUG_DISPLAY = 7;
- private final static int MSG_UNPLUG_DISPLAY = 8;
- private final static int MSG_UPDATE_DISPLAY_ARTWORK_SIZE = 9;
- private final static int MSG_SEEK_TO = 10;
private final static int MSG_POSITION_DRIFT_CHECK = 11;
- private final static int MSG_DISPLAY_WANTS_POS_SYNC = 12;
- private final static int MSG_UPDATE_METADATA = 13;
- private final static int MSG_REQUEST_METADATA_ARTWORK = 14;
- private final static int MSG_DISPLAY_ENABLE = 15;
private class EventHandler extends Handler {
public EventHandler(RemoteControlClient rcc, Looper looper) {
@@ -1361,63 +995,9 @@
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
- case MSG_REQUEST_PLAYBACK_STATE:
- synchronized (mCacheLock) {
- sendPlaybackState_syncCacheLock((IRemoteControlDisplay)msg.obj);
- }
- break;
- case MSG_REQUEST_METADATA:
- synchronized (mCacheLock) {
- sendMetadata_syncCacheLock((IRemoteControlDisplay)msg.obj);
- }
- break;
- case MSG_REQUEST_TRANSPORTCONTROL:
- synchronized (mCacheLock) {
- sendTransportControlInfo_syncCacheLock((IRemoteControlDisplay)msg.obj);
- }
- break;
- case MSG_REQUEST_ARTWORK:
- synchronized (mCacheLock) {
- sendArtwork_syncCacheLock((IRemoteControlDisplay)msg.obj,
- msg.arg1, msg.arg2);
- }
- break;
- case MSG_REQUEST_METADATA_ARTWORK:
- synchronized (mCacheLock) {
- sendMetadataWithArtwork_syncCacheLock((IRemoteControlDisplay)msg.obj,
- msg.arg1, msg.arg2);
- }
- break;
- case MSG_NEW_INTERNAL_CLIENT_GEN:
- onNewInternalClientGen(msg.arg1);
- break;
- case MSG_NEW_CURRENT_CLIENT_GEN:
- onNewCurrentClientGen(msg.arg1);
- break;
- case MSG_PLUG_DISPLAY:
- onPlugDisplay((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2);
- break;
- case MSG_UNPLUG_DISPLAY:
- onUnplugDisplay((IRemoteControlDisplay)msg.obj);
- break;
- case MSG_UPDATE_DISPLAY_ARTWORK_SIZE:
- onUpdateDisplayArtworkSize((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2);
- break;
- case MSG_SEEK_TO:
- onSeekTo(msg.arg1, ((Long)msg.obj).longValue());
- break;
case MSG_POSITION_DRIFT_CHECK:
onPositionDriftCheck();
break;
- case MSG_DISPLAY_WANTS_POS_SYNC:
- onDisplayWantsSync((IRemoteControlDisplay)msg.obj, msg.arg1 == 1);
- break;
- case MSG_UPDATE_METADATA:
- onUpdateMetadata(msg.arg1, msg.arg2, msg.obj);
- break;
- case MSG_DISPLAY_ENABLE:
- onDisplayEnable((IRemoteControlDisplay)msg.obj, msg.arg1 == 1);
- break;
default:
Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
}
@@ -1425,346 +1005,8 @@
}
//===========================================================
- // Communication with the IRemoteControlDisplay (the displays known to the system)
-
- private void sendPlaybackState_syncCacheLock(IRemoteControlDisplay target) {
- if (mCurrentClientGenId == mInternalClientGenId) {
- if (target != null) {
- try {
- target.setPlaybackState(mInternalClientGenId,
- mPlaybackState, mPlaybackStateChangeTimeMs, mPlaybackPositionMs,
- mPlaybackSpeed);
- } catch (RemoteException e) {
- Log.e(TAG, "Error in setPlaybackState() for dead display " + target, e);
- }
- return;
- }
- // target == null implies all displays must be updated
- final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
- while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = displayIterator.next();
- if (di.mEnabled) {
- try {
- di.mRcDisplay.setPlaybackState(mInternalClientGenId,
- mPlaybackState, mPlaybackStateChangeTimeMs, mPlaybackPositionMs,
- mPlaybackSpeed);
- } catch (RemoteException e) {
- Log.e(TAG, "Error in setPlaybackState(), dead display " + di.mRcDisplay, e);
- displayIterator.remove();
- }
- }
- }
- }
- }
-
- private void sendMetadata_syncCacheLock(IRemoteControlDisplay target) {
- if (mCurrentClientGenId == mInternalClientGenId) {
- if (target != null) {
- try {
- target.setMetadata(mInternalClientGenId, mMetadata);
- } catch (RemoteException e) {
- Log.e(TAG, "Error in setMetadata() for dead display " + target, e);
- }
- return;
- }
- // target == null implies all displays must be updated
- final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
- while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = displayIterator.next();
- if (di.mEnabled) {
- try {
- di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
- } catch (RemoteException e) {
- Log.e(TAG, "Error in setMetadata(), dead display " + di.mRcDisplay, e);
- displayIterator.remove();
- }
- }
- }
- }
- }
-
- private void sendTransportControlInfo_syncCacheLock(IRemoteControlDisplay target) {
- if (mCurrentClientGenId == mInternalClientGenId) {
- if (target != null) {
- try {
- target.setTransportControlInfo(mInternalClientGenId,
- mTransportControlFlags, mPlaybackPositionCapabilities);
- } catch (RemoteException e) {
- Log.e(TAG, "Error in setTransportControlFlags() for dead display " + target,
- e);
- }
- return;
- }
- // target == null implies all displays must be updated
- final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
- while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = displayIterator.next();
- if (di.mEnabled) {
- try {
- di.mRcDisplay.setTransportControlInfo(mInternalClientGenId,
- mTransportControlFlags, mPlaybackPositionCapabilities);
- } catch (RemoteException e) {
- Log.e(TAG, "Error in setTransportControlFlags(), dead display " + di.mRcDisplay,
- e);
- displayIterator.remove();
- }
- }
- }
- }
- }
-
- private void sendArtwork_syncCacheLock(IRemoteControlDisplay target, int w, int h) {
- // FIXME modify to cache all requested sizes?
- if (mCurrentClientGenId == mInternalClientGenId) {
- if (target != null) {
- final DisplayInfoForClient di = new DisplayInfoForClient(target, w, h);
- sendArtworkToDisplay(di);
- return;
- }
- // target == null implies all displays must be updated
- final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
- while (displayIterator.hasNext()) {
- if (!sendArtworkToDisplay(displayIterator.next())) {
- displayIterator.remove();
- }
- }
- }
- }
-
- /**
- * Send artwork to an IRemoteControlDisplay.
- * @param di encapsulates the IRemoteControlDisplay that will receive the artwork, and its
- * dimension requirements.
- * @return false if there was an error communicating with the IRemoteControlDisplay.
- */
- private boolean sendArtworkToDisplay(DisplayInfoForClient di) {
- if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
- Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork,
- di.mArtworkExpectedWidth, di.mArtworkExpectedHeight);
- try {
- di.mRcDisplay.setArtwork(mInternalClientGenId, artwork);
- } catch (RemoteException e) {
- Log.e(TAG, "Error in sendArtworkToDisplay(), dead display " + di.mRcDisplay, e);
- return false;
- }
- }
- return true;
- }
-
- private void sendMetadataWithArtwork_syncCacheLock(IRemoteControlDisplay target, int w, int h) {
- // FIXME modify to cache all requested sizes?
- if (mCurrentClientGenId == mInternalClientGenId) {
- if (target != null) {
- try {
- if ((w > 0) && (h > 0)) {
- Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork, w, h);
- target.setAllMetadata(mInternalClientGenId, mMetadata, artwork);
- } else {
- target.setMetadata(mInternalClientGenId, mMetadata);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Error in set(All)Metadata() for dead display " + target, e);
- }
- return;
- }
- // target == null implies all displays must be updated
- final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
- while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = displayIterator.next();
- try {
- if (di.mEnabled) {
- if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
- Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork,
- di.mArtworkExpectedWidth, di.mArtworkExpectedHeight);
- di.mRcDisplay.setAllMetadata(mInternalClientGenId, mMetadata, artwork);
- } else {
- di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Error when setting metadata, dead display " + di.mRcDisplay, e);
- displayIterator.remove();
- }
- }
- }
- }
-
- //===========================================================
- // Communication with AudioService
-
- private static IAudioService sService;
-
- private static IAudioService getService()
- {
- if (sService != null) {
- return sService;
- }
- IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
- sService = IAudioService.Stub.asInterface(b);
- return sService;
- }
-
- private void sendAudioServiceNewPlaybackInfo_syncCacheLock(int what, int value) {
- if (mRcseId == RCSE_ID_UNREGISTERED) {
- return;
- }
- //Log.d(TAG, "sending to AudioService key=" + what + ", value=" + value);
- IAudioService service = getService();
- try {
- service.setPlaybackInfoForRcc(mRcseId, what, value);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in setPlaybackInfoForRcc", e);
- }
- }
-
- private void sendAudioServiceNewPlaybackState_syncCacheLock() {
- if (mRcseId == RCSE_ID_UNREGISTERED) {
- return;
- }
- IAudioService service = getService();
- try {
- service.setPlaybackStateForRcc(mRcseId,
- mPlaybackState, mPlaybackPositionMs, mPlaybackSpeed);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in setPlaybackStateForRcc", e);
- }
- }
-
- //===========================================================
// Message handlers
- private void onNewInternalClientGen(int clientGeneration) {
- synchronized (mCacheLock) {
- // this remote control client is told it is the "focused" one:
- // it implies that now (mCurrentClientGenId == mInternalClientGenId) is true
- mInternalClientGenId = clientGeneration;
- }
- }
-
- private void onNewCurrentClientGen(int clientGeneration) {
- synchronized (mCacheLock) {
- mCurrentClientGenId = clientGeneration;
- }
- }
-
- /** pre-condition rcd != null */
- private void onPlugDisplay(IRemoteControlDisplay rcd, int w, int h) {
- synchronized(mCacheLock) {
- // do we have this display already?
- boolean displayKnown = false;
- final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
- while (displayIterator.hasNext() && !displayKnown) {
- final DisplayInfoForClient di = displayIterator.next();
- displayKnown = di.mRcDisplay.asBinder().equals(rcd.asBinder());
- if (displayKnown) {
- // this display was known but the change in artwork size will cause the
- // artwork to be refreshed
- if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
- di.mArtworkExpectedWidth = w;
- di.mArtworkExpectedHeight = h;
- if (!sendArtworkToDisplay(di)) {
- displayIterator.remove();
- }
- }
- }
- }
- if (!displayKnown) {
- mRcDisplays.add(new DisplayInfoForClient(rcd, w, h));
- }
- }
- }
-
- /** pre-condition rcd != null */
- private void onUnplugDisplay(IRemoteControlDisplay rcd) {
- synchronized(mCacheLock) {
- Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
- while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = displayIterator.next();
- if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
- displayIterator.remove();
- break;
- }
- }
- // list of RCDs has changed, reevaluate whether position check is still needed
- boolean oldNeedsPositionSync = mNeedsPositionSync;
- boolean newNeedsPositionSync = false;
- displayIterator = mRcDisplays.iterator();
- while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = displayIterator.next();
- if (di.mWantsPositionSync) {
- newNeedsPositionSync = true;
- break;
- }
- }
- mNeedsPositionSync = newNeedsPositionSync;
- if (oldNeedsPositionSync != mNeedsPositionSync) {
- // update needed?
- initiateCheckForDrift_syncCacheLock();
- }
- }
- }
-
- /** pre-condition rcd != null */
- private void onUpdateDisplayArtworkSize(IRemoteControlDisplay rcd, int w, int h) {
- synchronized(mCacheLock) {
- final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
- while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = displayIterator.next();
- if (di.mRcDisplay.asBinder().equals(rcd.asBinder()) &&
- ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h))) {
- di.mArtworkExpectedWidth = w;
- di.mArtworkExpectedHeight = h;
- if (di.mEnabled) {
- if (!sendArtworkToDisplay(di)) {
- displayIterator.remove();
- }
- }
- break;
- }
- }
- }
- }
-
- /** pre-condition rcd != null */
- private void onDisplayWantsSync(IRemoteControlDisplay rcd, boolean wantsSync) {
- synchronized(mCacheLock) {
- boolean oldNeedsPositionSync = mNeedsPositionSync;
- boolean newNeedsPositionSync = false;
- final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
- // go through the list of RCDs and for each entry, check both whether this is the RCD
- // that gets upated, and whether the list has one entry that wants position sync
- while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = displayIterator.next();
- if (di.mEnabled) {
- if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
- di.mWantsPositionSync = wantsSync;
- }
- if (di.mWantsPositionSync) {
- newNeedsPositionSync = true;
- }
- }
- }
- mNeedsPositionSync = newNeedsPositionSync;
- if (oldNeedsPositionSync != mNeedsPositionSync) {
- // update needed?
- initiateCheckForDrift_syncCacheLock();
- }
- }
- }
-
- /** pre-condition rcd != null */
- private void onDisplayEnable(IRemoteControlDisplay rcd, boolean enable) {
- synchronized(mCacheLock) {
- final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
- while (displayIterator.hasNext()) {
- final DisplayInfoForClient di = displayIterator.next();
- if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
- di.mEnabled = enable;
- }
- }
- }
- }
-
private void onSeekTo(int generationId, long timeMs) {
synchronized (mCacheLock) {
if ((mCurrentClientGenId == generationId) && (mPositionUpdateListener != null)) {
@@ -1785,42 +1027,6 @@
// Internal utilities
/**
- * Scale a bitmap to fit the smallest dimension by uniformly scaling the incoming bitmap.
- * If the bitmap fits, then do nothing and return the original.
- *
- * @param bitmap
- * @param maxWidth
- * @param maxHeight
- * @return
- */
-
- private Bitmap scaleBitmapIfTooBig(Bitmap bitmap, int maxWidth, int maxHeight) {
- if (bitmap != null) {
- final int width = bitmap.getWidth();
- final int height = bitmap.getHeight();
- if (width > maxWidth || height > maxHeight) {
- float scale = Math.min((float) maxWidth / width, (float) maxHeight / height);
- int newWidth = Math.round(scale * width);
- int newHeight = Math.round(scale * height);
- Bitmap.Config newConfig = bitmap.getConfig();
- if (newConfig == null) {
- newConfig = Bitmap.Config.ARGB_8888;
- }
- Bitmap outBitmap = Bitmap.createBitmap(newWidth, newHeight, newConfig);
- Canvas canvas = new Canvas(outBitmap);
- Paint paint = new Paint();
- paint.setAntiAlias(true);
- paint.setFilterBitmap(true);
- canvas.drawBitmap(bitmap, null,
- new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint);
- bitmap = outBitmap;
- }
- }
- return bitmap;
- }
-
-
- /**
* Returns whether, for the given playback state, the playback position is expected to
* be changing.
* @param playstate the playback state to evaluate
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index 3711585..76c7299 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -19,11 +19,17 @@
import android.app.ActivityManager;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.media.IRemoteControlDisplay;
import android.media.MediaMetadataEditor;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionLegacyHelper;
+import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -34,6 +40,7 @@
import android.view.KeyEvent;
import java.lang.ref.WeakReference;
+import java.util.List;
/**
* The RemoteController class is used to control media playback, display and update media metadata
@@ -56,6 +63,7 @@
private final static int TRANSPORT_UNKNOWN = 0;
private final static String TAG = "RemoteController";
private final static boolean DEBUG = false;
+ private final static boolean USE_SESSIONS = true;
private final static Object mGenLock = new Object();
private final static Object mInfoLock = new Object();
private final RcDisplay mRcd;
@@ -64,6 +72,11 @@
private final int mMaxBitmapDimension;
private MetadataEditor mMetadataEditor;
+ private MediaSessionManager mSessionManager;
+ private MediaSessionManager.SessionListener mSessionListener
+ = new TopTransportSessionListener();
+ private MediaController.Callback mSessionCb = new MediaControllerCallback();
+
/**
* Synchronized on mGenLock
*/
@@ -79,6 +92,8 @@
private int mArtworkWidth = -1;
private int mArtworkHeight = -1;
private boolean mEnabled = true;
+ // synchronized on mInfoLock, for USE_SESSION apis.
+ private MediaController mCurrentSession;
/**
* Class constructor.
@@ -123,6 +138,8 @@
mContext = context;
mRcd = new RcDisplay(this);
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mSessionManager = (MediaSessionManager) context
+ .getSystemService(Context.MEDIA_SESSION_SERVICE);
if (ActivityManager.isLowRamDeviceStatic()) {
mMaxBitmapDimension = MAX_BITMAP_DIMENSION;
@@ -194,8 +211,15 @@
* @hide
*/
public String getRemoteControlClientPackageName() {
- return mClientPendingIntentCurrent != null ?
- mClientPendingIntentCurrent.getCreatorPackage() : null;
+ if (USE_SESSIONS) {
+ synchronized (mInfoLock) {
+ return mCurrentSession != null ? mCurrentSession.getSessionInfo().getPackageName()
+ : null;
+ }
+ } else {
+ return mClientPendingIntentCurrent != null ?
+ mClientPendingIntentCurrent.getCreatorPackage() : null;
+ }
}
/**
@@ -215,22 +239,38 @@
* @see OnClientUpdateListener#onClientPlaybackStateUpdate(int, long, long, float)
*/
public long getEstimatedMediaPosition() {
- if (mLastPlaybackInfo != null) {
- if (!RemoteControlClient.playbackPositionShouldMove(mLastPlaybackInfo.mState)) {
- return mLastPlaybackInfo.mCurrentPosMs;
+ if (USE_SESSIONS) {
+ synchronized (mInfoLock) {
+ if (mCurrentSession != null) {
+ PlaybackState state = mCurrentSession.getPlaybackState();
+ if (state != null) {
+ return state.getPosition();
+ }
+ }
}
-
- // Take the current position at the time of state change and estimate.
- final long thenPos = mLastPlaybackInfo.mCurrentPosMs;
- if (thenPos < 0) {
- return -1;
+ } else {
+ final PlaybackInfo lastPlaybackInfo;
+ synchronized (mInfoLock) {
+ lastPlaybackInfo = mLastPlaybackInfo;
}
+ if (lastPlaybackInfo != null) {
+ if (!RemoteControlClient.playbackPositionShouldMove(lastPlaybackInfo.mState)) {
+ return lastPlaybackInfo.mCurrentPosMs;
+ }
- final long now = SystemClock.elapsedRealtime();
- final long then = mLastPlaybackInfo.mStateChangeTimeMs;
- final long sinceThen = now - then;
- final long scaledSinceThen = (long) (sinceThen * mLastPlaybackInfo.mSpeed);
- return thenPos + scaledSinceThen;
+ // Take the current position at the time of state change and
+ // estimate.
+ final long thenPos = lastPlaybackInfo.mCurrentPosMs;
+ if (thenPos < 0) {
+ return -1;
+ }
+
+ final long now = SystemClock.elapsedRealtime();
+ final long then = lastPlaybackInfo.mStateChangeTimeMs;
+ final long sinceThen = now - then;
+ final long scaledSinceThen = (long) (sinceThen * lastPlaybackInfo.mSpeed);
+ return thenPos + scaledSinceThen;
+ }
}
return -1;
}
@@ -267,30 +307,40 @@
if (!KeyEvent.isMediaKey(keyEvent.getKeyCode())) {
throw new IllegalArgumentException("not a media key event");
}
- final PendingIntent pi;
- synchronized(mInfoLock) {
- if (!mIsRegistered) {
- Log.e(TAG, "Cannot use sendMediaKeyEvent() from an unregistered RemoteController");
- return false;
- }
- if (!mEnabled) {
- Log.e(TAG, "Cannot use sendMediaKeyEvent() from a disabled RemoteController");
- return false;
- }
- pi = mClientPendingIntentCurrent;
- }
- if (pi != null) {
- Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
- intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
- try {
- pi.send(mContext, 0, intent);
- } catch (CanceledException e) {
- Log.e(TAG, "Error sending intent for media button down: ", e);
+ if (USE_SESSIONS) {
+ synchronized (mInfoLock) {
+ if (mCurrentSession != null) {
+ return mCurrentSession.dispatchMediaButtonEvent(keyEvent);
+ }
return false;
}
} else {
- Log.i(TAG, "No-op when sending key click, no receiver right now");
- return false;
+ final PendingIntent pi;
+ synchronized (mInfoLock) {
+ if (!mIsRegistered) {
+ Log.e(TAG,
+ "Cannot use sendMediaKeyEvent() from an unregistered RemoteController");
+ return false;
+ }
+ if (!mEnabled) {
+ Log.e(TAG, "Cannot use sendMediaKeyEvent() from a disabled RemoteController");
+ return false;
+ }
+ pi = mClientPendingIntentCurrent;
+ }
+ if (pi != null) {
+ Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ try {
+ pi.send(mContext, 0, intent);
+ } catch (CanceledException e) {
+ Log.e(TAG, "Error sending intent for media button down: ", e);
+ return false;
+ }
+ } else {
+ Log.i(TAG, "No-op when sending key click, no receiver right now");
+ return false;
+ }
}
return true;
}
@@ -311,11 +361,19 @@
if (timeMs < 0) {
throw new IllegalArgumentException("illegal negative time value");
}
- final int genId;
- synchronized (mGenLock) {
- genId = mClientGenerationIdCurrent;
+ if (USE_SESSIONS) {
+ synchronized (mInfoLock) {
+ if (mCurrentSession != null) {
+ mCurrentSession.getTransportControls().seekTo(timeMs);
+ }
+ }
+ } else {
+ final int genId;
+ synchronized (mGenLock) {
+ genId = mClientGenerationIdCurrent;
+ }
+ mAudioManager.setRemoteControlClientPlaybackPosition(genId, timeMs);
}
- mAudioManager.setRemoteControlClientPlaybackPosition(genId, timeMs);
return true;
}
@@ -430,7 +488,6 @@
return editor;
}
-
/**
* A class to read the metadata published by a {@link RemoteControlClient}, or send a
* {@link RemoteControlClient} new values for keys that can be edited.
@@ -477,26 +534,41 @@
if (!mMetadataChanged) {
return;
}
- final int genId;
- synchronized(mGenLock) {
- genId = mClientGenerationIdCurrent;
- }
- synchronized(mInfoLock) {
- if (mEditorMetadata.containsKey(
- String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) {
- Rating rating = (Rating) getObject(
- MediaMetadataEditor.RATING_KEY_BY_USER, null);
- mAudioManager.updateRemoteControlClientMetadata(genId,
- MediaMetadataEditor.RATING_KEY_BY_USER,
- rating);
- } else {
- Log.e(TAG, "no metadata to apply");
+ if (USE_SESSIONS) {
+ synchronized (mInfoLock) {
+ if (mCurrentSession != null) {
+ if (mEditorMetadata.containsKey(
+ String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) {
+ Rating rating = (Rating) getObject(
+ MediaMetadataEditor.RATING_KEY_BY_USER, null);
+ if (rating != null) {
+ mCurrentSession.getTransportControls().setRating(rating);
+ }
+ }
+ }
}
- // NOT setting mApplied to true as this type of MetadataEditor will be applied
- // multiple times, whenever the user of a RemoteController needs to change the
- // metadata (e.g. user changes the rating of a song more than once during playback)
- mApplied = false;
+ } else {
+ final int genId;
+ synchronized(mGenLock) {
+ genId = mClientGenerationIdCurrent;
+ }
+ synchronized(mInfoLock) {
+ if (mEditorMetadata.containsKey(
+ String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) {
+ Rating rating = (Rating) getObject(
+ MediaMetadataEditor.RATING_KEY_BY_USER, null);
+ mAudioManager.updateRemoteControlClientMetadata(genId,
+ MediaMetadataEditor.RATING_KEY_BY_USER,
+ rating);
+ } else {
+ Log.e(TAG, "no metadata to apply");
+ }
+ }
}
+ // NOT setting mApplied to true as this type of MetadataEditor will be applied
+ // multiple times, whenever the user of a RemoteController needs to change the
+ // metadata (e.g. user changes the rating of a song more than once during playback)
+ mApplied = false;
}
}
@@ -649,6 +721,46 @@
}
}
+ /**
+ * This receives updates when the current session changes. This is
+ * registered to receive the updates on the handler thread so it can call
+ * directly into the appropriate methods.
+ */
+ private class MediaControllerCallback extends MediaController.Callback {
+ @Override
+ public void onPlaybackStateChanged(PlaybackState state) {
+ onNewPlaybackState(state);
+ }
+
+ @Override
+ public void onMetadataChanged(MediaMetadata metadata) {
+ onNewMediaMetadata(metadata);
+ }
+ }
+
+ /**
+ * Listens for changes to the active session stack and replaces the
+ * currently tracked session if it has changed.
+ */
+ private class TopTransportSessionListener extends MediaSessionManager.SessionListener {
+ @Override
+ public void onActiveSessionsChanged(List<MediaController> controllers) {
+ int size = controllers.size();
+ for (int i = 0; i < size; i++) {
+ MediaController controller = controllers.get(i);
+ long flags = controller.getFlags();
+ // We only care about sessions that handle transport controls,
+ // which will be true for apps using RCC
+ if ((flags & MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS) != 0) {
+ updateController(controller);
+ return;
+ }
+ }
+ updateController(null);
+ }
+
+ }
+
//==================================================
// Event handling
private final EventHandler mEventHandler;
@@ -658,6 +770,8 @@
private final static int MSG_NEW_METADATA = 3; // msg always has non-null obj parameter
private final static int MSG_CLIENT_CHANGE = 4;
private final static int MSG_DISPLAY_ENABLE = 5;
+ private final static int MSG_NEW_PLAYBACK_STATE = 6;
+ private final static int MSG_NEW_MEDIA_METADATA = 7;
private class EventHandler extends Handler {
@@ -686,12 +800,46 @@
case MSG_DISPLAY_ENABLE:
onDisplayEnable(msg.arg1 == 1);
break;
+ case MSG_NEW_PLAYBACK_STATE:
+ // same as new playback info but using new apis
+ onNewPlaybackState((PlaybackState) msg.obj);
+ break;
+ case MSG_NEW_MEDIA_METADATA:
+ onNewMediaMetadata((MediaMetadata) msg.obj);
+ break;
default:
Log.e(TAG, "unknown event " + msg.what);
}
}
}
+ /**
+ * @hide
+ */
+ void startListeningToSessions() {
+ final ComponentName listenerComponent = new ComponentName(mContext,
+ mOnClientUpdateListener.getClass());
+ mSessionManager.addActiveSessionsListener(mSessionListener, listenerComponent,
+ ActivityManager.getCurrentUser());
+ mSessionListener.onActiveSessionsChanged(mSessionManager
+ .getActiveSessions(listenerComponent));
+ if (DEBUG) {
+ Log.d(TAG, "Registered session listener with component " + listenerComponent
+ + " for user " + ActivityManager.getCurrentUser());
+ }
+ }
+
+ /**
+ * @hide
+ */
+ void stopListeningToSessions() {
+ mSessionManager.removeActiveSessionsListener(mSessionListener);
+ if (DEBUG) {
+ Log.d(TAG, "Unregistered session listener for user "
+ + ActivityManager.getCurrentUser());
+ }
+ }
+
/** If the msg is already queued, replace it with this one. */
private static final int SENDMSG_REPLACE = 0;
/** If the msg is already queued, ignore this one and leave the old. */
@@ -713,6 +861,7 @@
handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delayMs);
}
+ ///////////// These calls are used by the old APIs with RCC and RCD //////////////////////
private void onNewPendingIntent(int genId, PendingIntent pi) {
synchronized(mGenLock) {
if (mClientGenerationIdCurrent != genId) {
@@ -848,6 +997,86 @@
}
}
+ ///////////// These calls are used by the new APIs with Sessions //////////////////////
+ private void updateController(MediaController controller) {
+ if (DEBUG) {
+ Log.d(TAG, "Updating controller to " + controller + " previous controller is "
+ + mCurrentSession);
+ }
+ synchronized (mInfoLock) {
+ if (controller == null) {
+ if (mCurrentSession != null) {
+ mCurrentSession.removeCallback(mSessionCb);
+ mCurrentSession = null;
+ sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE,
+ 0 /* genId */, 1 /* clearing */, null /* obj */, 0 /* delay */);
+ }
+ } else if (mCurrentSession == null
+ || !controller.getSessionInfo().getId()
+ .equals(mCurrentSession.getSessionInfo().getId())) {
+ if (mCurrentSession != null) {
+ mCurrentSession.removeCallback(mSessionCb);
+ }
+ sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE,
+ 0 /* genId */, 0 /* clearing */, null /* obj */, 0 /* delay */);
+ mCurrentSession = controller;
+ mCurrentSession.addCallback(mSessionCb, mEventHandler);
+
+ PlaybackState state = controller.getPlaybackState();
+ sendMsg(mEventHandler, MSG_NEW_PLAYBACK_STATE, SENDMSG_REPLACE,
+ 0 /* genId */, 0, state /* obj */, 0 /* delay */);
+
+ MediaMetadata metadata = controller.getMetadata();
+ sendMsg(mEventHandler, MSG_NEW_MEDIA_METADATA, SENDMSG_REPLACE,
+ 0 /* arg1 */, 0 /* arg2 */, metadata /* obj */, 0 /* delay */);
+ }
+ // else same controller, no need to update
+ }
+ }
+
+ private void onNewPlaybackState(PlaybackState state) {
+ final OnClientUpdateListener l;
+ synchronized (mInfoLock) {
+ l = this.mOnClientUpdateListener;
+ }
+ if (l != null) {
+ int playstate = state == null ? RemoteControlClient.PLAYSTATE_NONE : PlaybackState
+ .getRccStateFromState(state.getState());
+ if (state == null || state.getPosition() == PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
+ l.onClientPlaybackStateUpdate(playstate);
+ } else {
+ l.onClientPlaybackStateUpdate(playstate, state.getLastPositionUpdateTime(),
+ state.getPosition(), state.getPlaybackRate());
+ }
+ if (state != null) {
+ l.onClientTransportControlUpdate(PlaybackState.getRccControlFlagsFromActions(state
+ .getActions()));
+ }
+ }
+ }
+
+ private void onNewMediaMetadata(MediaMetadata metadata) {
+ if (metadata == null) {
+ // RemoteController only handles non-null metadata
+ return;
+ }
+ final OnClientUpdateListener l;
+ final MetadataEditor metadataEditor;
+ // prepare the received Bundle to be used inside a MetadataEditor
+ synchronized(mInfoLock) {
+ l = mOnClientUpdateListener;
+ boolean canRate = mCurrentSession != null
+ && mCurrentSession.getRatingType() != Rating.RATING_NONE;
+ long editableKeys = canRate ? MediaMetadataEditor.RATING_KEY_BY_USER : 0;
+ Bundle legacyMetadata = MediaSessionLegacyHelper.getOldMetadata(metadata);
+ mMetadataEditor = new MetadataEditor(legacyMetadata, editableKeys);
+ metadataEditor = mMetadataEditor;
+ }
+ if (l != null) {
+ l.onClientMetadataUpdate(metadataEditor);
+ }
+ }
+
//==================================================
private static class PlaybackInfo {
int mState;
diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java
index 06063de..b0e182d 100644
--- a/media/java/android/media/SubtitleTrack.java
+++ b/media/java/android/media/SubtitleTrack.java
@@ -83,7 +83,7 @@
* indicating the last section of the run. Calls from different
* runs must not be intermixed.
*
- * @param data
+ * @param data subtitle data byte buffer
* @param eos true if this is the last section of the run.
* @param runID mostly-unique ID for this run of data. Subtitle cues
* with runID of 0 are discarded immediately after
@@ -92,10 +92,8 @@
* with other runID-s are discarded at the end of the
* run, which defaults to the latest timestamp of
* any of its cues (with this runID).
- *
- * TODO use ByteBuffer
*/
- public abstract void onData(String data, boolean eos, long runID);
+ public abstract void onData(byte[] data, boolean eos, long runID);
/**
* Called when adding the subtitle rendering widget to the view hierarchy,
diff --git a/media/java/android/media/TtmlRenderer.java b/media/java/android/media/TtmlRenderer.java
index 0309334..75133c9 100644
--- a/media/java/android/media/TtmlRenderer.java
+++ b/media/java/android/media/TtmlRenderer.java
@@ -563,28 +563,35 @@
}
@Override
- public void onData(String data, boolean eos, long runID) {
- // implement intermixing restriction for TTML.
- synchronized(mParser) {
- if (mCurrentRunID != null && runID != mCurrentRunID) {
- throw new IllegalStateException(
- "Run #" + mCurrentRunID +
- " in progress. Cannot process run #" + runID);
- }
- mCurrentRunID = runID;
- mParsingData += data;
- if (eos) {
- try {
- mParser.parse(mParsingData, mCurrentRunID);
- } catch (XmlPullParserException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
+ public void onData(byte[] data, boolean eos, long runID) {
+ try {
+ // TODO: handle UTF-8 conversion properly
+ String str = new String(data, "UTF-8");
+
+ // implement intermixing restriction for TTML.
+ synchronized(mParser) {
+ if (mCurrentRunID != null && runID != mCurrentRunID) {
+ throw new IllegalStateException(
+ "Run #" + mCurrentRunID +
+ " in progress. Cannot process run #" + runID);
}
- finishedRun(runID);
- mParsingData = "";
- mCurrentRunID = null;
+ mCurrentRunID = runID;
+ mParsingData += str;
+ if (eos) {
+ try {
+ mParser.parse(mParsingData, mCurrentRunID);
+ } catch (XmlPullParserException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ finishedRun(runID);
+ mParsingData = "";
+ mCurrentRunID = null;
+ }
}
+ } catch (java.io.UnsupportedEncodingException e) {
+ Log.w(TAG, "subtitle data is not UTF-8 encoded: " + e);
}
}
diff --git a/media/java/android/media/WebVttRenderer.java b/media/java/android/media/WebVttRenderer.java
index 7977988..a9374d5 100644
--- a/media/java/android/media/WebVttRenderer.java
+++ b/media/java/android/media/WebVttRenderer.java
@@ -1001,22 +1001,28 @@
}
@Override
- public void onData(String data, boolean eos, long runID) {
- // implement intermixing restriction for WebVTT only for now
- synchronized(mParser) {
- if (mCurrentRunID != null && runID != mCurrentRunID) {
- throw new IllegalStateException(
- "Run #" + mCurrentRunID +
- " in progress. Cannot process run #" + runID);
+ public void onData(byte[] data, boolean eos, long runID) {
+ try {
+ String str = new String(data, "UTF-8");
+
+ // implement intermixing restriction for WebVTT only for now
+ synchronized(mParser) {
+ if (mCurrentRunID != null && runID != mCurrentRunID) {
+ throw new IllegalStateException(
+ "Run #" + mCurrentRunID +
+ " in progress. Cannot process run #" + runID);
+ }
+ mCurrentRunID = runID;
+ mParser.parse(str);
+ if (eos) {
+ finishedRun(runID);
+ mParser.eos();
+ mRegions.clear();
+ mCurrentRunID = null;
+ }
}
- mCurrentRunID = runID;
- mParser.parse(data);
- if (eos) {
- finishedRun(runID);
- mParser.eos();
- mRegions.clear();
- mCurrentRunID = null;
- }
+ } catch (java.io.UnsupportedEncodingException e) {
+ Log.w(TAG, "subtitle data is not UTF-8 encoded: " + e);
}
}
diff --git a/core/java/android/app/task/Task.aidl b/media/java/android/media/session/IActiveSessionsListener.aidl
similarity index 63%
copy from core/java/android/app/task/Task.aidl
copy to media/java/android/media/session/IActiveSessionsListener.aidl
index 1f25439..e5e24bc 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/media/java/android/media/session/IActiveSessionsListener.aidl
@@ -1,5 +1,4 @@
-/**
- * Copyright (C) 2014 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,7 +13,14 @@
* limitations under the License.
*/
-package android.app.task;
+package android.media.session;
-parcelable Task;
-
\ No newline at end of file
+import android.media.session.MediaSessionToken;
+
+/**
+ * Listens for changes to the list of active sessions.
+ * @hide
+ */
+oneway interface IActiveSessionsListener {
+ void onActiveSessionsChanged(in List<MediaSessionToken> sessions);
+}
\ No newline at end of file
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 9ce0692..f0cd785 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -19,6 +19,7 @@
import android.media.MediaMetadata;
import android.media.Rating;
import android.media.session.ISessionControllerCallback;
+import android.media.session.MediaSessionInfo;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -35,6 +36,8 @@
void unregisterCallbackListener(in ISessionControllerCallback cb);
boolean isTransportControlEnabled();
void showRoutePicker();
+ MediaSessionInfo getSessionInfo();
+ long getFlags();
// These commands are for the TransportController
void play();
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 6d9888f..bd1fa85 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -16,6 +16,7 @@
package android.media.session;
import android.content.ComponentName;
+import android.media.session.IActiveSessionsListener;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
import android.os.Bundle;
@@ -30,4 +31,7 @@
List<IBinder> getSessions(in ComponentName compName, int userId);
void dispatchMediaKeyEvent(in KeyEvent keyEvent, boolean needWakeLock);
void dispatchAdjustVolumeBy(int suggestedStream, int delta, int flags);
+ void addSessionsListener(in IActiveSessionsListener listener, in ComponentName compName,
+ int userId);
+ void removeSessionsListener(in IActiveSessionsListener listener);
}
\ No newline at end of file
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index caff1ad..5ca7daa 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -57,6 +57,7 @@
private final Object mLock = new Object();
private boolean mCbRegistered = false;
+ private MediaSessionInfo mInfo;
private TransportControls mTransportController;
@@ -174,6 +175,21 @@
}
/**
+ * Get the flags for this session.
+ *
+ * @return The current set of flags for the session.
+ * @hide
+ */
+ public long getFlags() {
+ try {
+ return mSessionBinder.getFlags();
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling getFlags.", e);
+ }
+ return 0;
+ }
+
+ /**
* Adds a callback to receive updates from the Session. Updates will be
* posted on the caller's thread.
*
@@ -246,6 +262,23 @@
}
}
+ /**
+ * Get the info for the session this controller is connected to.
+ *
+ * @return The session info for the connected session.
+ * @hide
+ */
+ public MediaSessionInfo getSessionInfo() {
+ if (mInfo == null) {
+ try {
+ mInfo = mSessionBinder.getSessionInfo();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in getSessionInfo.", e);
+ }
+ }
+ return mInfo;
+ }
+
/*
* @hide
*/
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 7972639..4ba1351 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -277,6 +277,7 @@
throw new IllegalArgumentException("volumeProvider may not be null!");
}
mVolumeProvider = volumeProvider;
+ volumeProvider.setSession(this);
try {
mBinder.configureVolumeHandling(VOLUME_TYPE_REMOTE, volumeProvider.getVolumeControl(),
@@ -522,6 +523,24 @@
}
}
+ /**
+ * Notify the system that the remove volume changed.
+ *
+ * @param provider The provider that is handling volume changes.
+ * @hide
+ */
+ void notifyRemoteVolumeChanged(RemoteVolumeProvider provider) {
+ if (provider == null || provider != mVolumeProvider) {
+ Log.w(TAG, "Received update from stale volume provider");
+ return;
+ }
+ try {
+ mBinder.setCurrentVolume(provider.onGetCurrentVolume());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in notifyVolumeChanged", e);
+ }
+ }
+
private void dispatchPlay() {
postToTransportCallbacks(TransportMessageHandler.MSG_PLAY);
}
@@ -963,27 +982,26 @@
@Override
public void onRouteStateChange(int state) throws RemoteException {
// TODO
-
}
- /*
- * (non-Javadoc)
- * @see android.media.session.ISessionCallback#onAdjustVolumeBy(int)
- */
@Override
public void onAdjustVolumeBy(int delta) throws RemoteException {
- // TODO(epastern): Auto-generated method stub
-
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ if (session.mVolumeProvider != null) {
+ session.mVolumeProvider.onAdjustVolumeBy(delta);
+ }
+ }
}
- /*
- * (non-Javadoc)
- * @see android.media.session.ISessionCallback#onSetVolumeTo(int)
- */
@Override
public void onSetVolumeTo(int value) throws RemoteException {
- // TODO(epastern): Auto-generated method stub
-
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ if (session.mVolumeProvider != null) {
+ session.mVolumeProvider.onSetVolumeTo(value);
+ }
+ }
}
}
diff --git a/media/java/android/media/session/MediaSessionInfo.aidl b/media/java/android/media/session/MediaSessionInfo.aidl
new file mode 100644
index 0000000..63dca9a
--- /dev/null
+++ b/media/java/android/media/session/MediaSessionInfo.aidl
@@ -0,0 +1,18 @@
+/* Copyright 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.media.session;
+
+parcelable MediaSessionInfo;
diff --git a/media/java/android/media/session/MediaSessionInfo.java b/media/java/android/media/session/MediaSessionInfo.java
index f701211..4dc1c09 100644
--- a/media/java/android/media/session/MediaSessionInfo.java
+++ b/media/java/android/media/session/MediaSessionInfo.java
@@ -26,18 +26,21 @@
public final class MediaSessionInfo implements Parcelable {
private final String mId;
private final String mPackageName;
+ private final int mPid;
/**
* @hide
*/
- public MediaSessionInfo(String id, String packageName) {
+ public MediaSessionInfo(String id, String packageName, int pid) {
mId = id;
mPackageName = packageName;
+ mPid = pid;
}
private MediaSessionInfo(Parcel in) {
mId = in.readString();
mPackageName = in.readString();
+ mPid = in.readInt();
}
/**
@@ -58,9 +61,13 @@
return mId;
}
+ public int getPid() {
+ return mPid;
+ }
+
@Override
public String toString() {
- return "SessionInfo {id=" + mId + ", pkg=" + mPackageName + "}";
+ return "SessionInfo {id=" + mId + ", pkg=" + mPackageName + ", pid=" + mPid + "}";
}
@Override
@@ -72,6 +79,7 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mId);
dest.writeString(mPackageName);
+ dest.writeInt(mPid);
}
public static final Parcelable.Creator<MediaSessionInfo> CREATOR
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 099f601..801844f 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -20,6 +20,10 @@
import android.app.PendingIntent.CanceledException;
import android.content.Context;
import android.content.Intent;
+import android.media.MediaMetadata;
+import android.media.MediaMetadataEditor;
+import android.media.MediaMetadataRetriever;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.ArrayMap;
@@ -64,6 +68,88 @@
return sInstance;
}
+ public static Bundle getOldMetadata(MediaMetadata metadata) {
+ Bundle oldMetadata = new Bundle();
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ALBUM),
+ metadata.getString(MediaMetadata.METADATA_KEY_ALBUM));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_ART)) {
+ oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK),
+ metadata.getBitmap(MediaMetadata.METADATA_KEY_ART));
+ } else if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART)) {
+ // Fall back to album art if the track art wasn't available
+ oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK),
+ metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ARTIST)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST),
+ metadata.getString(MediaMetadata.METADATA_KEY_ALBUM_ARTIST));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_ARTIST)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ARTIST),
+ metadata.getString(MediaMetadata.METADATA_KEY_ARTIST));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_AUTHOR)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_AUTHOR),
+ metadata.getString(MediaMetadata.METADATA_KEY_AUTHOR));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_COMPILATION)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_COMPILATION),
+ metadata.getString(MediaMetadata.METADATA_KEY_COMPILATION));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_COMPOSER)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_COMPOSER),
+ metadata.getString(MediaMetadata.METADATA_KEY_COMPOSER));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_DATE)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_DATE),
+ metadata.getString(MediaMetadata.METADATA_KEY_DATE));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_DISC_NUMBER)) {
+ oldMetadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER),
+ metadata.getLong(MediaMetadata.METADATA_KEY_DISC_NUMBER));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
+ oldMetadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_DURATION),
+ metadata.getLong(MediaMetadata.METADATA_KEY_DURATION));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_GENRE)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_GENRE),
+ metadata.getString(MediaMetadata.METADATA_KEY_GENRE));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_NUM_TRACKS)) {
+ oldMetadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS),
+ metadata.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_RATING)) {
+ oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.RATING_KEY_BY_OTHERS),
+ metadata.getRating(MediaMetadata.METADATA_KEY_RATING));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_USER_RATING)) {
+ oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER),
+ metadata.getRating(MediaMetadata.METADATA_KEY_USER_RATING));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_TITLE)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_TITLE),
+ metadata.getString(MediaMetadata.METADATA_KEY_TITLE));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_TRACK_NUMBER)) {
+ oldMetadata.putLong(
+ String.valueOf(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER),
+ metadata.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_WRITER)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_WRITER),
+ metadata.getString(MediaMetadata.METADATA_KEY_WRITER));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_YEAR)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_YEAR),
+ metadata.getString(MediaMetadata.METADATA_KEY_YEAR));
+ }
+ return oldMetadata;
+ }
+
public MediaSession getSession(PendingIntent pi) {
SessionHolder holder = mSessions.get(pi);
return holder == null ? null : holder.mSession;
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 9e8b0d3..2e6b86e 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -96,10 +96,13 @@
}
/**
- * Get a list of controllers for all ongoing sessions. This requires the
- * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
- * the calling app. You may also retrieve this list if your app is an
- * enabled notification listener using the
+ * Get a list of controllers for all ongoing sessions. The controllers will
+ * be provided in priority order with the most important controller at index
+ * 0.
+ * <p>
+ * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL
+ * permission be held by the calling app. You may also retrieve this list if
+ * your app is an enabled notification listener using the
* {@link NotificationListenerService} APIs, in which case you must pass the
* {@link ComponentName} of your enabled listener.
*
@@ -130,7 +133,8 @@
ArrayList<MediaController> controllers = new ArrayList<MediaController>();
try {
List<IBinder> binders = mService.getSessions(notificationListener, userId);
- for (int i = binders.size() - 1; i >= 0; i--) {
+ int size = binders.size();
+ for (int i = 0; i < size; i++) {
MediaController controller = MediaController.fromBinder(ISessionController.Stub
.asInterface(binders.get(i)));
controllers.add(controller);
@@ -142,6 +146,50 @@
}
/**
+ * Add a listener to be notified when the list of active sessions
+ * changes.This requires the
+ * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
+ * the calling app. You may also retrieve this list if your app is an
+ * enabled notification listener using the
+ * {@link NotificationListenerService} APIs, in which case you must pass the
+ * {@link ComponentName} of your enabled listener.
+ *
+ * @param sessionListener The listener to add.
+ * @param notificationListener The enabled notification listener component.
+ * May be null.
+ * @param userId The userId to listen for changes on.
+ * @hide
+ */
+ public void addActiveSessionsListener(SessionListener sessionListener,
+ ComponentName notificationListener, int userId) {
+ if (sessionListener == null) {
+ throw new IllegalArgumentException("listener may not be null");
+ }
+ try {
+ mService.addSessionsListener(sessionListener.mStub, notificationListener, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in addActiveSessionsListener.", e);
+ }
+ }
+
+ /**
+ * Stop receiving active sessions updates on the specified listener.
+ *
+ * @param listener The listener to remove.
+ * @hide
+ */
+ public void removeActiveSessionsListener(SessionListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener may not be null");
+ }
+ try {
+ mService.removeSessionsListener(listener.mStub);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in removeActiveSessionsListener.", e);
+ }
+ }
+
+ /**
* Send a media key event. The receiver will be selected automatically.
*
* @param keyEvent The KeyEvent to send.
@@ -184,4 +232,36 @@
Log.e(TAG, "Failed to send adjust volume.", e);
}
}
+
+ /**
+ * Listens for changes to the list of active sessions. This can be added
+ * using {@link #addActiveSessionsListener}.
+ *
+ * @hide
+ */
+ public static abstract class SessionListener {
+ /**
+ * Called when the list of active sessions has changed. This can be due
+ * to a session being added or removed or the order of sessions
+ * changing. The controllers will be provided in priority order with the
+ * most important controller at index 0.
+ *
+ * @param controllers The updated list of controllers for the user that
+ * changed.
+ */
+ public abstract void onActiveSessionsChanged(List<MediaController> controllers);
+
+ private final IActiveSessionsListener.Stub mStub = new IActiveSessionsListener.Stub() {
+ @Override
+ public void onActiveSessionsChanged(List<MediaSessionToken> tokens)
+ throws RemoteException {
+ ArrayList<MediaController> controllers = new ArrayList<MediaController>();
+ int size = tokens.size();
+ for (int i = 0; i < size; i++) {
+ controllers.add(MediaController.fromToken(tokens.get(i)));
+ }
+ SessionListener.this.onActiveSessionsChanged(controllers);
+ }
+ };
+ }
}
diff --git a/media/java/android/media/session/MediaSessionToken.java b/media/java/android/media/session/MediaSessionToken.java
index 86f5662..e599189 100644
--- a/media/java/android/media/session/MediaSessionToken.java
+++ b/media/java/android/media/session/MediaSessionToken.java
@@ -31,7 +31,7 @@
/**
* @hide
*/
- MediaSessionToken(ISessionController binder) {
+ public MediaSessionToken(ISessionController binder) {
mBinder = binder;
}
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index e09ac3f..3b3f249 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -432,6 +432,8 @@
return STATE_REWINDING;
case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
return STATE_SKIPPING_TO_PREVIOUS;
+ case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+ return STATE_SKIPPING_TO_NEXT;
case RemoteControlClient.PLAYSTATE_STOPPED:
return STATE_STOPPED;
default:
@@ -440,6 +442,41 @@
}
/**
+ * Get the {@link RemoteControlClient} state for the given
+ * {@link PlaybackState} state.
+ *
+ * @param state The state used by {@link PlaybackState}.
+ * @return The equivalent state used by {@link RemoteControlClient}.
+ * @hide
+ */
+ public static int getRccStateFromState(int state) {
+ switch (state) {
+ case STATE_BUFFERING:
+ return RemoteControlClient.PLAYSTATE_BUFFERING;
+ case STATE_ERROR:
+ return RemoteControlClient.PLAYSTATE_ERROR;
+ case STATE_FAST_FORWARDING:
+ return RemoteControlClient.PLAYSTATE_FAST_FORWARDING;
+ case STATE_NONE:
+ return RemoteControlClient.PLAYSTATE_NONE;
+ case STATE_PAUSED:
+ return RemoteControlClient.PLAYSTATE_PAUSED;
+ case STATE_PLAYING:
+ return RemoteControlClient.PLAYSTATE_PLAYING;
+ case STATE_REWINDING:
+ return RemoteControlClient.PLAYSTATE_REWINDING;
+ case STATE_SKIPPING_TO_PREVIOUS:
+ return RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS;
+ case STATE_SKIPPING_TO_NEXT:
+ return RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS;
+ case STATE_STOPPED:
+ return RemoteControlClient.PLAYSTATE_STOPPED;
+ default:
+ return -1;
+ }
+ }
+
+ /**
* @hide
*/
public static long getActionsFromRccControlFlags(int rccFlags) {
@@ -454,6 +491,21 @@
return actions;
}
+ /**
+ * @hide
+ */
+ public static int getRccControlFlagsFromActions(long actions) {
+ int rccFlags = 0;
+ long action = 1;
+ while (action <= actions && action < Integer.MAX_VALUE) {
+ if ((action & actions) != 0) {
+ rccFlags |= getRccFlagForAction(action);
+ }
+ action = action << 1;
+ }
+ return rccFlags;
+ }
+
private static long getActionForRccFlag(int flag) {
switch (flag) {
case RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS:
@@ -480,6 +532,35 @@
return 0;
}
+ private static int getRccFlagForAction(long action) {
+ // We only care about the lower set of actions that can map to rcc
+ // flags.
+ int testAction = action < Integer.MAX_VALUE ? (int) action : 0;
+ switch (testAction) {
+ case (int) ACTION_SKIP_TO_PREVIOUS:
+ return RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS;
+ case (int) ACTION_REWIND:
+ return RemoteControlClient.FLAG_KEY_MEDIA_REWIND;
+ case (int) ACTION_PLAY:
+ return RemoteControlClient.FLAG_KEY_MEDIA_PLAY;
+ case (int) ACTION_PLAY_PAUSE:
+ return RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE;
+ case (int) ACTION_PAUSE:
+ return RemoteControlClient.FLAG_KEY_MEDIA_PAUSE;
+ case (int) ACTION_STOP:
+ return RemoteControlClient.FLAG_KEY_MEDIA_STOP;
+ case (int) ACTION_FAST_FORWARD:
+ return RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD;
+ case (int) ACTION_SKIP_TO_NEXT:
+ return RemoteControlClient.FLAG_KEY_MEDIA_NEXT;
+ case (int) ACTION_SEEK_TO:
+ return RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE;
+ case (int) ACTION_SET_RATING:
+ return RemoteControlClient.FLAG_KEY_MEDIA_RATING;
+ }
+ return 0;
+ }
+
public static final Parcelable.Creator<PlaybackState> CREATOR
= new Parcelable.Creator<PlaybackState>() {
@Override
diff --git a/media/java/android/media/session/RemoteVolumeProvider.java b/media/java/android/media/session/RemoteVolumeProvider.java
index 47f672f3..606b1d7 100644
--- a/media/java/android/media/session/RemoteVolumeProvider.java
+++ b/media/java/android/media/session/RemoteVolumeProvider.java
@@ -15,6 +15,9 @@
*/
package android.media.session;
+import android.os.RemoteException;
+import android.util.Log;
+
/**
* Handles requests to adjust or set the volume on a session. This is also used
* to push volume updates back to the session after a request has been handled.
@@ -22,6 +25,7 @@
* {@link MediaSession#setPlaybackToRemote}.
*/
public abstract class RemoteVolumeProvider {
+ private static final String TAG = "RemoteVolumeProvider";
/**
* The volume is fixed and can not be modified. Requests to change volume
@@ -46,6 +50,8 @@
private final int mControlType;
private final int mMaxVolume;
+ private MediaSession mSession;
+
/**
* Create a new volume provider for handling volume events. You must specify
* the type of volume control and the maximum volume that can be used.
@@ -88,7 +94,7 @@
* Notify the system that the remote playback's volume has been changed.
*/
public final void notifyVolumeChanged() {
- // TODO
+ mSession.notifyRemoteVolumeChanged(this);
}
/**
@@ -107,4 +113,11 @@
*/
public void onAdjustVolumeBy(int delta) {
}
+
+ /**
+ * @hide
+ */
+ void setSession(MediaSession session) {
+ mSession = session;
+ }
}
\ No newline at end of file
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 5e650c2..3f0405d 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -144,15 +144,41 @@
/**
* Builds a URI that points to all programs on a given channel.
*
+ * @param channelId The ID of the channel to return programs for.
+ */
+ public static final Uri buildProgramsUriForChannel(long channelId) {
+ return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
+ .appendPath(PATH_CHANNEL).appendPath(String.valueOf(channelId))
+ .appendPath(PATH_PROGRAM).build();
+ }
+
+ /**
+ * Builds a URI that points to all programs on a given channel.
+ *
* @param channelUri The URI of the channel to return programs for.
*/
public static final Uri buildProgramsUriForChannel(Uri channelUri) {
if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
throw new IllegalArgumentException("Not a channel: " + channelUri);
}
- String channelId = String.valueOf(ContentUris.parseId(channelUri));
- return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
- .appendPath(PATH_CHANNEL).appendPath(channelId).appendPath(PATH_PROGRAM).build();
+ return buildProgramsUriForChannel(ContentUris.parseId(channelUri));
+ }
+
+ /**
+ * Builds a URI that points to programs on a specific channel whose schedules overlap with the
+ * given time frame.
+ *
+ * @param channelId The ID of the channel to return programs for.
+ * @param startTime The start time used to filter programs. The returned programs should have
+ * {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time.
+ * @param endTime The end time used to filter programs. The returned programs should have
+ * {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time.
+ */
+ public static final Uri buildProgramsUriForChannel(long channelId, long startTime,
+ long endTime) {
+ Uri uri = buildProgramsUriForChannel(channelId);
+ return uri.buildUpon().appendQueryParameter(PARAM_START_TIME, String.valueOf(startTime))
+ .appendQueryParameter(PARAM_END_TIME, String.valueOf(endTime)).build();
}
/**
@@ -167,9 +193,10 @@
*/
public static final Uri buildProgramsUriForChannel(Uri channelUri, long startTime,
long endTime) {
- Uri uri = buildProgramsUriForChannel(channelUri);
- return uri.buildUpon().appendQueryParameter(PARAM_START_TIME, String.valueOf(startTime))
- .appendQueryParameter(PARAM_END_TIME, String.valueOf(endTime)).build();
+ if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
+ throw new IllegalArgumentException("Not a channel: " + channelUri);
+ }
+ return buildProgramsUriForChannel(ContentUris.parseId(channelUri), startTime, endTime);
}
/**
@@ -272,6 +299,15 @@
/** A generic channel type. */
public static final int TYPE_OTHER = 0x0;
+ /** The channel type for NTSC. */
+ public static final int TYPE_NTSC = 0x1;
+
+ /** The channel type for PAL. */
+ public static final int TYPE_PAL = 0x2;
+
+ /** The channel type for SECAM. */
+ public static final int TYPE_SECAM = 0x3;
+
/** The special channel type used for pass-through inputs such as HDMI. */
public static final int TYPE_PASSTHROUGH = 0x00010000;
@@ -306,7 +342,7 @@
public static final int TYPE_ATSC_C = 0x00030200;
/** The channel type for ATSC-M/H (mobile/handheld). */
- public static final int TYPE_ATSC_M_H = 0x00030200;
+ public static final int TYPE_ATSC_M_H = 0x00030300;
/** The channel type for ISDB-T (terrestrial). */
public static final int TYPE_ISDB_T = 0x00040000;
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 9525c08..7b8f2ec 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -26,6 +26,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -46,6 +47,27 @@
private static final String TAG = "TvInputInfo";
/**
+ * TV input type: the TV input service is not handling input from hardware. For example,
+ * services showing streaming from the internet falls into this type.
+ */
+ public static final int TYPE_VIRTUAL = 0;
+
+ // Should be in sync with hardware/libhardware/include/hardware/tv_input.h
+
+ /**
+ * TV input type: the TV input service is HDMI. (e.g. HDMI 1)
+ */
+ public static final int TYPE_HDMI = 1;
+ /**
+ * TV input type: the TV input service is a tuner. (e.g. terrestrial tuner)
+ */
+ public static final int TYPE_TUNER = 2;
+ /**
+ * TV input type: the TV input service is stateless pass-through. (e.g. RGB, composite, etc.)
+ */
+ public static final int TYPE_PASSTHROUGH = 3;
+
+ /**
* The name of the TV input service to provide to the setup activity and settings activity.
*/
public static final String EXTRA_SERVICE_NAME = "serviceName";
@@ -58,6 +80,7 @@
// Attributes from XML meta data.
private String mSetupActivity;
private String mSettingsActivity;
+ private int mType;
/**
* Create a new instance of the TvInputInfo class,
@@ -105,6 +128,11 @@
Log.d(TAG, "Settings activity loaded. [" + input.mSettingsActivity + "] for "
+ si.name);
}
+ input.mType = sa.getInt(
+ com.android.internal.R.styleable.TvInputService_tvInputType, TYPE_VIRTUAL);
+ if (DEBUG) {
+ Log.d(TAG, "Type loaded. [" + input.mType + "] for " + si.name);
+ }
sa.recycle();
return input;
@@ -179,6 +207,13 @@
}
/**
+ * Returns the type of this TV input service.
+ */
+ public int getType() {
+ return mType;
+ }
+
+ /**
* Loads the user-displayed label for this TV input service.
*
* @param pm Supplies a PackageManager used to load the TV input's resources.
@@ -189,6 +224,18 @@
return mService.loadLabel(pm);
}
+ /**
+ * Loads the user-displayed icon for this TV input service.
+ *
+ * @param pm Supplies a PackageManager used to load the TV input's resources.
+ * @return a Drawable containing the TV input's icon. If the TV input does not have
+ * an icon, application icon is returned. If it's unavailable too, system default is
+ * returned.
+ */
+ public Drawable loadIcon(PackageManager pm) {
+ return mService.serviceInfo.loadIcon(pm);
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index c2459a6..2831d9e 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -33,12 +33,13 @@
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
+import android.view.ViewGroup;
import android.view.ViewRootImpl;
/**
* View playing TV
*/
-public class TvView extends SurfaceView {
+public class TvView extends ViewGroup {
private static final String TAG = "TvView";
// STOPSHIP: Turn debugging off.
private static final boolean DEBUG = true;
@@ -57,6 +58,7 @@
private final Handler mHandler = new Handler();
private TvInputManager.Session mSession;
+ private final SurfaceView mSurfaceView;
private Surface mSurface;
private boolean mOverlayViewCreated;
private Rect mOverlayViewFrame;
@@ -64,6 +66,8 @@
private MySessionCallback mSessionCallback;
private TvInputListener mListener;
private OnUnhandledInputEventListener mOnUnhandledInputEventListener;
+ private boolean mHasStreamVolume;
+ private float mStreamVolume;
private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
@Override
@@ -122,7 +126,14 @@
public TvView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- getHolder().addCallback(mSurfaceHolderCallback);
+ mSurfaceView = new SurfaceView(context, attrs, defStyleAttr) {
+ @Override
+ protected void updateWindow(boolean force, boolean redrawNeeded) {
+ super.updateWindow(force, redrawNeeded);
+ relayoutSessionOverlayView();
+ }};
+ mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback);
+ addView(mSurfaceView);
mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
}
@@ -143,7 +154,10 @@
*/
public void setStreamVolume(float volume) {
if (DEBUG) Log.d(TAG, "setStreamVolume(" + volume + ")");
+ mHasStreamVolume = true;
+ mStreamVolume = volume;
if (mSession == null) {
+ // Volume will be set once the connection has been made.
return;
}
mSession.setStreamVolume(volume);
@@ -305,11 +319,26 @@
super.onDetachedFromWindow();
}
- /** @hide */
@Override
- protected void updateWindow(boolean force, boolean redrawNeeded) {
- super.updateWindow(force, redrawNeeded);
- relayoutSessionOverlayView();
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ mSurfaceView.layout(0, 0, right - left, bottom - top);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ mSurfaceView.measure(widthMeasureSpec, heightMeasureSpec);
+ int width = mSurfaceView.getMeasuredWidth();
+ int height = mSurfaceView.getMeasuredHeight();
+ int childState = mSurfaceView.getMeasuredState();
+ setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, childState),
+ resolveSizeAndState(height, heightMeasureSpec,
+ childState << MEASURED_HEIGHT_STATE_SHIFT));
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ super.setVisibility(visibility);
+ mSurfaceView.setVisibility(visibility);
}
private void release() {
@@ -476,6 +505,9 @@
}
createSessionOverlayView();
mSession.tune(mChannelUri);
+ if (mHasStreamVolume) {
+ mSession.setStreamVolume(mStreamVolume);
+ }
} else {
if (mListener != null) {
mListener.onError(mInputId, ERROR_BUSY);
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 157dd49..fbe5340 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -24,6 +24,7 @@
#include <SkBitmap.h>
#include <media/IMediaHTTPService.h>
#include <media/mediametadataretriever.h>
+#include <media/mediascanner.h>
#include <private/media/VideoFrame.h>
#include "jni.h"
@@ -337,17 +338,13 @@
return NULL;
}
- unsigned int len = mediaAlbumArt->mSize;
- char* data = (char*) mediaAlbumArt + sizeof(MediaAlbumArt);
- jbyteArray array = env->NewByteArray(len);
+ jbyteArray array = env->NewByteArray(mediaAlbumArt->size());
if (!array) { // OutOfMemoryError exception has already been thrown.
ALOGE("getEmbeddedPicture: OutOfMemoryError is thrown.");
} else {
- jbyte* bytes = env->GetByteArrayElements(array, NULL);
- if (bytes != NULL) {
- memcpy(bytes, data, len);
- env->ReleaseByteArrayElements(array, bytes, 0);
- }
+ const jbyte* data =
+ reinterpret_cast<const jbyte*>(mediaAlbumArt->data());
+ env->SetByteArrayRegion(array, 0, mediaAlbumArt->size(), data);
}
// No need to delete mediaAlbumArt here
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 6730e0a..321c2e3 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -348,17 +348,16 @@
}
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- MediaAlbumArt* mediaAlbumArt =
- reinterpret_cast<MediaAlbumArt*>(mp->extractAlbumArt(fd));
- if (mediaAlbumArt != NULL) {
+ MediaAlbumArt* mediaAlbumArt = mp->extractAlbumArt(fd);
+ if (mediaAlbumArt == NULL) {
return NULL;
}
- jbyteArray array = env->NewByteArray(mediaAlbumArt->mSize);
+ jbyteArray array = env->NewByteArray(mediaAlbumArt->size());
if (array != NULL) {
- jbyte* bytes = env->GetByteArrayElements(array, NULL);
- memcpy(bytes, &mediaAlbumArt->mData[0], mediaAlbumArt->mSize);
- env->ReleaseByteArrayElements(array, bytes, 0);
+ const jbyte* data =
+ reinterpret_cast<const jbyte*>(mediaAlbumArt->data());
+ env->SetByteArrayRegion(array, 0, mediaAlbumArt->size(), data);
}
done:
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RangeTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RangeTest.java
new file mode 100644
index 0000000..d90a4bc
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RangeTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.mediaframeworktest.unit;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Range;
+import android.util.Rational;
+
+/**
+ * <pre>
+ * adb shell am instrument \
+ * -e class 'com.android.mediaframeworktest.unit.RangeTest' \
+ * -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
+ * </pre>
+ */
+public class RangeTest extends junit.framework.TestCase {
+
+ @SmallTest
+ public void testConstructor() {
+ // Trivial, same range
+ Range<Integer> intRange = new Range<Integer>(1, 1);
+
+ assertLower(intRange, 1);
+ assertUpper(intRange, 1);
+
+ // Different values in range
+ Range<Integer> intRange2 = new Range<Integer>(100, 200);
+ assertLower(intRange2, 100);
+ assertUpper(intRange2, 200);
+
+ Range<Float> floatRange = new Range<Float>(Float.NEGATIVE_INFINITY,
+ Float.POSITIVE_INFINITY);
+ assertLower(floatRange, Float.NEGATIVE_INFINITY);
+ assertUpper(floatRange, Float.POSITIVE_INFINITY);
+ }
+
+ @SmallTest
+ public void testIllegalValues() {
+ // Test NPEs
+ try {
+ new Range<Integer>(null, null);
+ fail("Expected exception to be thrown for (null, null)");
+ } catch (NullPointerException e) {
+ // OK: both args are null
+ }
+
+ try {
+ new Range<Integer>(null, 0);
+ fail("Expected exception to be thrown for (null, 0)");
+ } catch (NullPointerException e) {
+ // OK: left arg is null
+ }
+
+ try {
+ new Range<Integer>(0, null);
+ fail("Expected exception to be thrown for (0, null)");
+ } catch (NullPointerException e) {
+ // OK: right arg is null
+ }
+
+ // Test IAEs
+
+ try {
+ new Range<Integer>(50, -50);
+ fail("Expected exception to be thrown for (50, -50)");
+ } catch (IllegalArgumentException e) {
+ // OK: 50 > -50 so it fails
+ }
+
+ try {
+ new Range<Float>(0.0f, Float.NEGATIVE_INFINITY);
+ fail("Expected exception to be thrown for (0.0f, -Infinity)");
+ } catch (IllegalArgumentException e) {
+ // OK: 0.0f is > NEGATIVE_INFINITY, so it fails
+ }
+ }
+
+ @SmallTest
+ public void testEquals() {
+ Range<Float> oneHalf = Range.create(1.0f, 2.0f);
+ Range<Float> oneHalf2 = new Range<Float>(1.0f, 2.0f);
+ assertEquals(oneHalf, oneHalf2);
+ assertHashCodeEquals(oneHalf, oneHalf2);
+
+ Range<Float> twoThirds = new Range<Float>(2.0f, 3.0f);
+ Range<Float> twoThirds2 = Range.create(2.0f, 3.0f);
+ assertEquals(twoThirds, twoThirds2);
+ assertHashCodeEquals(twoThirds, twoThirds2);
+
+ Range<Rational> negativeOneTenthPositiveOneTenth =
+ new Range<Rational>(new Rational(-1, 10), new Rational(1, 10));
+ Range<Rational> negativeOneTenthPositiveOneTenth2 =
+ Range.create(new Rational(-1, 10), new Rational(1, 10));
+ assertEquals(negativeOneTenthPositiveOneTenth, negativeOneTenthPositiveOneTenth2);
+ assertHashCodeEquals(negativeOneTenthPositiveOneTenth, negativeOneTenthPositiveOneTenth2);
+ }
+
+ @SmallTest
+ public void testInRange() {
+ Range<Integer> hundredOneTwo = Range.create(100, 200);
+
+ assertInRange(hundredOneTwo, 100);
+ assertInRange(hundredOneTwo, 200);
+ assertInRange(hundredOneTwo, 150);
+ assertOutOfRange(hundredOneTwo, 99);
+ assertOutOfRange(hundredOneTwo, 201);
+ assertOutOfRange(hundredOneTwo, 100000);
+
+ Range<Float> infinities = Range.create(Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
+
+ assertInRange(infinities, Float.NEGATIVE_INFINITY);
+ assertInRange(infinities, Float.POSITIVE_INFINITY);
+ assertInRange(infinities, 0.0f);
+ assertOutOfRange(infinities, Float.NaN);
+
+ Range<Rational> negativeOneTenthPositiveOneTenth =
+ new Range<Rational>(new Rational(-1, 10), new Rational(1, 10));
+ assertInRange(negativeOneTenthPositiveOneTenth, new Rational(-1, 10));
+ assertInRange(negativeOneTenthPositiveOneTenth, new Rational(1, 10));
+ assertInRange(negativeOneTenthPositiveOneTenth, Rational.ZERO);
+ assertOutOfRange(negativeOneTenthPositiveOneTenth, new Rational(-100, 1));
+ assertOutOfRange(negativeOneTenthPositiveOneTenth, new Rational(100, 1));
+ }
+
+ private static <T extends Comparable<? super T>> void assertInRange(Range<T> object, T needle) {
+ assertAction("in-range", object, needle, true, object.inRange(needle));
+ }
+
+ private static <T extends Comparable<? super T>> void assertOutOfRange(Range<T> object,
+ T needle) {
+ assertAction("out-of-range", object, needle, false, object.inRange(needle));
+ }
+
+ private static <T extends Comparable<? super T>> void assertUpper(Range<T> object, T expected) {
+ assertAction("upper", object, expected, object.getUpper());
+ }
+
+ private static <T extends Comparable<? super T>> void assertLower(Range<T> object, T expected) {
+ assertAction("lower", object, expected, object.getLower());
+ }
+
+ private static <T, T2> void assertAction(String action, T object, T2 expected,
+ T2 actual) {
+ assertEquals("Expected " + object + " " + action + " to be ",
+ expected, actual);
+ }
+
+ private static <T, T2> void assertAction(String action, T object, T2 needle, boolean expected,
+ boolean actual) {
+ String expectedMessage = expected ? action : ("not " + action);
+ assertEquals("Expected " + needle + " to be " + expectedMessage + " of " + object,
+ expected, actual);
+ }
+
+ private static <T extends Comparable<? super T>> void assertHashCodeEquals(
+ Range<T> left, Range<T> right) {
+ assertEquals("Left hash code for " + left +
+ " expected to be equal to right hash code for " + right,
+ left.hashCode(), right.hashCode());
+ }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
index 18c0d3e..1bb7db9 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
@@ -19,6 +19,17 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Rational;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+
+import static android.util.Rational.*;
+
/**
* <pre>
* adb shell am instrument \
@@ -27,6 +38,22 @@
* </pre>
*/
public class RationalTest extends junit.framework.TestCase {
+
+ /** (1,1) */
+ private static final Rational UNIT = new Rational(1, 1);
+
+ /**
+ * Test @hide greatest common divisior functionality that cannot be tested in CTS.
+ */
+ @SmallTest
+ public void testGcd() {
+ assertEquals(1, Rational.gcd(1, 2));
+ assertEquals(1, Rational.gcd(2, 3));
+ assertEquals(78, Rational.gcd(5*78, 7*78));
+ assertEquals(1, Rational.gcd(-1, 2));
+ assertEquals(1, Rational.gcd(-2, 3));
+ }
+
@SmallTest
public void testConstructor() {
@@ -52,12 +79,12 @@
// Infinity.
r = new Rational(1, 0);
- assertEquals(0, r.getNumerator());
+ assertEquals(1, r.getNumerator());
assertEquals(0, r.getDenominator());
// Negative infinity.
r = new Rational(-1, 0);
- assertEquals(0, r.getNumerator());
+ assertEquals(-1, r.getNumerator());
assertEquals(0, r.getDenominator());
// NaN.
@@ -67,24 +94,6 @@
}
@SmallTest
- public void testGcd() {
- Rational r = new Rational(1, 2);
- assertEquals(1, r.gcd());
-
- Rational twoThirds = new Rational(2, 3);
- assertEquals(1, twoThirds.gcd());
-
- Rational moreComplicated2 = new Rational(5*78, 7*78);
- assertEquals(78, moreComplicated2.gcd());
-
- Rational oneHalf = new Rational(-1, 2);
- assertEquals(1, oneHalf.gcd());
-
- twoThirds = new Rational(-2, 3);
- assertEquals(1, twoThirds.gcd());
- }
-
- @SmallTest
public void testEquals() {
Rational r = new Rational(1, 2);
assertEquals(1, r.getNumerator());
@@ -118,7 +127,13 @@
assertEquals(moreComplicated, moreComplicated2);
assertEquals(moreComplicated2, moreComplicated);
- Rational nan = new Rational(0, 0);
+ // Zero is always equal to itself
+ Rational zero2 = new Rational(0, 100);
+ assertEquals(ZERO, zero2);
+ assertEquals(zero2, ZERO);
+
+ // NaN is always equal to itself
+ Rational nan = NaN;
Rational nan2 = new Rational(0, 0);
assertTrue(nan.equals(nan));
assertTrue(nan.equals(nan2));
@@ -127,9 +142,9 @@
assertFalse(r.equals(nan));
// Infinities of the same sign are equal.
- Rational posInf = new Rational(1, 0);
+ Rational posInf = POSITIVE_INFINITY;
Rational posInf2 = new Rational(2, 0);
- Rational negInf = new Rational(-1, 0);
+ Rational negInf = NEGATIVE_INFINITY;
Rational negInf2 = new Rational(-2, 0);
assertEquals(posInf, posInf);
assertEquals(negInf, negInf);
@@ -148,4 +163,349 @@
assertFalse(nan.equals(posInf));
assertFalse(nan.equals(negInf));
}
+
+ @SmallTest
+ public void testReduction() {
+ Rational moreComplicated = new Rational(5 * 78, 7 * 78);
+ assertEquals(new Rational(5, 7), moreComplicated);
+ assertEquals(5, moreComplicated.getNumerator());
+ assertEquals(7, moreComplicated.getDenominator());
+
+ Rational posInf = new Rational(5, 0);
+ assertEquals(1, posInf.getNumerator());
+ assertEquals(0, posInf.getDenominator());
+ assertEquals(POSITIVE_INFINITY, posInf);
+
+ Rational negInf = new Rational(-100, 0);
+ assertEquals(-1, negInf.getNumerator());
+ assertEquals(0, negInf.getDenominator());
+ assertEquals(NEGATIVE_INFINITY, negInf);
+
+ Rational zero = new Rational(0, -100);
+ assertEquals(0, zero.getNumerator());
+ assertEquals(1, zero.getDenominator());
+ assertEquals(ZERO, zero);
+
+ Rational flipSigns = new Rational(1, -1);
+ assertEquals(-1, flipSigns.getNumerator());
+ assertEquals(1, flipSigns.getDenominator());
+
+ Rational flipAndReduce = new Rational(100, -200);
+ assertEquals(-1, flipAndReduce.getNumerator());
+ assertEquals(2, flipAndReduce.getDenominator());
+ }
+
+ @SmallTest
+ public void testCompareTo() {
+ // unit is equal to itself
+ assertCompareEquals(UNIT, new Rational(1, 1));
+
+ // NaN is greater than anything but NaN
+ assertCompareEquals(NaN, new Rational(0, 0));
+ assertGreaterThan(NaN, UNIT);
+ assertGreaterThan(NaN, POSITIVE_INFINITY);
+ assertGreaterThan(NaN, NEGATIVE_INFINITY);
+ assertGreaterThan(NaN, ZERO);
+
+ // Positive infinity is greater than any other non-NaN
+ assertCompareEquals(POSITIVE_INFINITY, new Rational(1, 0));
+ assertGreaterThan(POSITIVE_INFINITY, UNIT);
+ assertGreaterThan(POSITIVE_INFINITY, NEGATIVE_INFINITY);
+ assertGreaterThan(POSITIVE_INFINITY, ZERO);
+
+ // Negative infinity is smaller than any other non-NaN
+ assertCompareEquals(NEGATIVE_INFINITY, new Rational(-1, 0));
+ assertLessThan(NEGATIVE_INFINITY, UNIT);
+ assertLessThan(NEGATIVE_INFINITY, POSITIVE_INFINITY);
+ assertLessThan(NEGATIVE_INFINITY, ZERO);
+
+ // A finite number with the same denominator is trivially comparable
+ assertGreaterThan(new Rational(3, 100), new Rational(1, 100));
+ assertGreaterThan(new Rational(3, 100), ZERO);
+
+ // Compare finite numbers with different divisors
+ assertGreaterThan(new Rational(5, 25), new Rational(1, 10));
+ assertGreaterThan(new Rational(5, 25), ZERO);
+
+ // Compare finite numbers with different signs
+ assertGreaterThan(new Rational(5, 25), new Rational(-1, 10));
+ assertLessThan(new Rational(-5, 25), ZERO);
+ }
+
+ @SmallTest
+ public void testConvenienceMethods() {
+ // isFinite
+ assertFinite(ZERO, true);
+ assertFinite(NaN, false);
+ assertFinite(NEGATIVE_INFINITY, false);
+ assertFinite(POSITIVE_INFINITY, false);
+ assertFinite(UNIT, true);
+
+ // isInfinite
+ assertInfinite(ZERO, false);
+ assertInfinite(NaN, false);
+ assertInfinite(NEGATIVE_INFINITY, true);
+ assertInfinite(POSITIVE_INFINITY, true);
+ assertInfinite(UNIT, false);
+
+ // isNaN
+ assertNaN(ZERO, false);
+ assertNaN(NaN, true);
+ assertNaN(NEGATIVE_INFINITY, false);
+ assertNaN(POSITIVE_INFINITY, false);
+ assertNaN(UNIT, false);
+
+ // isZero
+ assertZero(ZERO, true);
+ assertZero(NaN, false);
+ assertZero(NEGATIVE_INFINITY, false);
+ assertZero(POSITIVE_INFINITY, false);
+ assertZero(UNIT, false);
+ }
+
+ @SmallTest
+ public void testValueConversions() {
+ // Unit, simple case
+ assertValueEquals(UNIT, 1.0f);
+ assertValueEquals(UNIT, 1.0);
+ assertValueEquals(UNIT, 1L);
+ assertValueEquals(UNIT, 1);
+ assertValueEquals(UNIT, (short)1);
+
+ // Zero, simple case
+ assertValueEquals(ZERO, 0.0f);
+ assertValueEquals(ZERO, 0.0);
+ assertValueEquals(ZERO, 0L);
+ assertValueEquals(ZERO, 0);
+ assertValueEquals(ZERO, (short)0);
+
+ // NaN is 0 for integers, not-a-number for floating point
+ assertValueEquals(NaN, Float.NaN);
+ assertValueEquals(NaN, Double.NaN);
+ assertValueEquals(NaN, 0L);
+ assertValueEquals(NaN, 0);
+ assertValueEquals(NaN, (short)0);
+
+ // Positive infinity, saturates upwards for integers
+ assertValueEquals(POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
+ assertValueEquals(POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+ assertValueEquals(POSITIVE_INFINITY, Long.MAX_VALUE);
+ assertValueEquals(POSITIVE_INFINITY, Integer.MAX_VALUE);
+ assertValueEquals(POSITIVE_INFINITY, (short)-1);
+
+ // Negative infinity, saturates downwards for integers
+ assertValueEquals(NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
+ assertValueEquals(NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
+ assertValueEquals(NEGATIVE_INFINITY, Long.MIN_VALUE);
+ assertValueEquals(NEGATIVE_INFINITY, Integer.MIN_VALUE);
+ assertValueEquals(NEGATIVE_INFINITY, (short)0);
+
+ // Normal finite values, round down for integers
+ final Rational oneQuarter = new Rational(1, 4);
+ assertValueEquals(oneQuarter, 1.0f / 4.0f);
+ assertValueEquals(oneQuarter, 1.0 / 4.0);
+ assertValueEquals(oneQuarter, 0L);
+ assertValueEquals(oneQuarter, 0);
+ assertValueEquals(oneQuarter, (short)0);
+
+ final Rational nineFifths = new Rational(9, 5);
+ assertValueEquals(nineFifths, 9.0f / 5.0f);
+ assertValueEquals(nineFifths, 9.0 / 5.0);
+ assertValueEquals(nineFifths, 1L);
+ assertValueEquals(nineFifths, 1);
+ assertValueEquals(nineFifths, (short)1);
+
+ final Rational negativeHundred = new Rational(-1000, 10);
+ assertValueEquals(negativeHundred, -100.f / 1.f);
+ assertValueEquals(negativeHundred, -100.0 / 1.0);
+ assertValueEquals(negativeHundred, -100L);
+ assertValueEquals(negativeHundred, -100);
+ assertValueEquals(negativeHundred, (short)-100);
+
+ // Short truncates if the result is too large
+ assertValueEquals(new Rational(Integer.MAX_VALUE, 1), (short)Integer.MAX_VALUE);
+ assertValueEquals(new Rational(0x00FFFFFF, 1), (short)0x00FFFFFF);
+ assertValueEquals(new Rational(0x00FF00FF, 1), (short)0x00FF00FF);
+ }
+
+ @SmallTest
+ public void testSerialize() throws ClassNotFoundException, IOException {
+ /*
+ * Check correct [de]serialization
+ */
+ assertEqualsAfterSerializing(ZERO);
+ assertEqualsAfterSerializing(NaN);
+ assertEqualsAfterSerializing(NEGATIVE_INFINITY);
+ assertEqualsAfterSerializing(POSITIVE_INFINITY);
+ assertEqualsAfterSerializing(UNIT);
+ assertEqualsAfterSerializing(new Rational(100, 200));
+ assertEqualsAfterSerializing(new Rational(-100, 200));
+ assertEqualsAfterSerializing(new Rational(5, 1));
+ assertEqualsAfterSerializing(new Rational(Integer.MAX_VALUE, Integer.MIN_VALUE));
+
+ /*
+ * Check bad deserialization fails
+ */
+ try {
+ Rational badZero = createIllegalRational(0, 100); // [0, 100] , should be [0, 1]
+ Rational results = serializeRoundTrip(badZero);
+ fail("Deserializing " + results + " should not have succeeded");
+ } catch (InvalidObjectException e) {
+ // OK
+ }
+
+ try {
+ Rational badPosInfinity = createIllegalRational(100, 0); // [100, 0] , should be [1, 0]
+ Rational results = serializeRoundTrip(badPosInfinity);
+ fail("Deserializing " + results + " should not have succeeded");
+ } catch (InvalidObjectException e) {
+ // OK
+ }
+
+ try {
+ Rational badNegInfinity =
+ createIllegalRational(-100, 0); // [-100, 0] , should be [-1, 0]
+ Rational results = serializeRoundTrip(badNegInfinity);
+ fail("Deserializing " + results + " should not have succeeded");
+ } catch (InvalidObjectException e) {
+ // OK
+ }
+
+ try {
+ Rational badReduced = createIllegalRational(2, 4); // [2,4] , should be [1, 2]
+ Rational results = serializeRoundTrip(badReduced);
+ fail("Deserializing " + results + " should not have succeeded");
+ } catch (InvalidObjectException e) {
+ // OK
+ }
+
+ try {
+ Rational badReducedNeg = createIllegalRational(-2, 4); // [-2, 4] should be [-1, 2]
+ Rational results = serializeRoundTrip(badReducedNeg);
+ fail("Deserializing " + results + " should not have succeeded");
+ } catch (InvalidObjectException e) {
+ // OK
+ }
+ }
+
+ private static void assertValueEquals(Rational object, float expected) {
+ assertEquals("Checking floatValue() for " + object + ";",
+ expected, object.floatValue());
+ }
+
+ private static void assertValueEquals(Rational object, double expected) {
+ assertEquals("Checking doubleValue() for " + object + ";",
+ expected, object.doubleValue());
+ }
+
+ private static void assertValueEquals(Rational object, long expected) {
+ assertEquals("Checking longValue() for " + object + ";",
+ expected, object.longValue());
+ }
+
+ private static void assertValueEquals(Rational object, int expected) {
+ assertEquals("Checking intValue() for " + object + ";",
+ expected, object.intValue());
+ }
+
+ private static void assertValueEquals(Rational object, short expected) {
+ assertEquals("Checking shortValue() for " + object + ";",
+ expected, object.shortValue());
+ }
+
+ private static void assertFinite(Rational object, boolean expected) {
+ assertAction("finite", object, expected, object.isFinite());
+ }
+
+ private static void assertInfinite(Rational object, boolean expected) {
+ assertAction("infinite", object, expected, object.isInfinite());
+ }
+
+ private static void assertNaN(Rational object, boolean expected) {
+ assertAction("NaN", object, expected, object.isNaN());
+ }
+
+ private static void assertZero(Rational object, boolean expected) {
+ assertAction("zero", object, expected, object.isZero());
+ }
+
+ private static <T> void assertAction(String action, T object, boolean expected,
+ boolean actual) {
+ String expectedMessage = expected ? action : ("not " + action);
+ assertEquals("Expected " + object + " to be " + expectedMessage,
+ expected, actual);
+ }
+
+ private static <T extends Comparable<? super T>> void assertLessThan(T left, T right) {
+ assertTrue("Expected (LR) left " + left + " to be less than right " + right,
+ left.compareTo(right) < 0);
+ assertTrue("Expected (RL) left " + left + " to be less than right " + right,
+ right.compareTo(left) > 0);
+ }
+
+ private static <T extends Comparable<? super T>> void assertGreaterThan(T left, T right) {
+ assertTrue("Expected (LR) left " + left + " to be greater than right " + right,
+ left.compareTo(right) > 0);
+ assertTrue("Expected (RL) left " + left + " to be greater than right " + right,
+ right.compareTo(left) < 0);
+ }
+
+ private static <T extends Comparable<? super T>> void assertCompareEquals(T left, T right) {
+ assertTrue("Expected (LR) left " + left + " to be compareEquals to right " + right,
+ left.compareTo(right) == 0);
+ assertTrue("Expected (RL) left " + left + " to be compareEquals to right " + right,
+ right.compareTo(left) == 0);
+ }
+
+ private static <T extends Serializable> byte[] serialize(T obj) throws IOException {
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ try (ObjectOutputStream objectStream = new ObjectOutputStream(byteStream)) {
+ objectStream.writeObject(obj);
+ }
+ return byteStream.toByteArray();
+ }
+
+ private static <T extends Serializable> T deserialize(byte[] array, Class<T> klass)
+ throws IOException, ClassNotFoundException {
+ ByteArrayInputStream bais = new ByteArrayInputStream(array);
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ Object obj = ois.readObject();
+ return klass.cast(obj);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T extends Serializable> T serializeRoundTrip(T obj)
+ throws IOException, ClassNotFoundException {
+ Class<T> klass = (Class<T>) obj.getClass();
+ byte[] arr = serialize(obj);
+ T serialized = deserialize(arr, klass);
+ return serialized;
+ }
+
+ private static <T extends Serializable> void assertEqualsAfterSerializing(T obj)
+ throws ClassNotFoundException, IOException {
+ T serialized = serializeRoundTrip(obj);
+ assertEquals("Expected values to be equal after serialization round-trip", obj, serialized);
+ }
+
+ private static Rational createIllegalRational(int numerator, int denominator) {
+ Rational r = new Rational(numerator, denominator);
+ mutateField(r, "mNumerator", numerator);
+ mutateField(r, "mDenominator", denominator);
+ return r;
+ }
+
+ private static <T> void mutateField(T object, String name, int value) {
+ try {
+ Field f = object.getClass().getDeclaredField(name);
+ f.setAccessible(true);
+ f.set(object, value);
+ } catch (NoSuchFieldException e) {
+ throw new AssertionError(e);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(e);
+ } catch (IllegalArgumentException e) {
+ throw new AssertionError(e);
+ }
+ }
}
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
index 3dd988e..a4d292a 100644
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
+++ b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
@@ -104,7 +104,9 @@
int height;
meta->findInt32(kKeyWidth, &width);
meta->findInt32(kKeyHeight, &height);
- configBitmapSize(bm, getPrefConfig(k32Bit_SrcDepth, false), width, height);
+ configBitmapSize(
+ bm, SkColorTypeToBitmapConfig(getPrefColorType(k32Bit_SrcDepth, false)),
+ width, height);
// mode == DecodeBounds
if (mode == SkImageDecoder::kDecodeBounds_Mode) {
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 3f37ed1..b09bc2e 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -171,3 +171,8 @@
{
return static_cast<Sensor const*>(sensor)->getStringType().string();
}
+
+int ASensor_getReportingMode(ASensor const* sensor)
+{
+ return static_cast<Sensor const*>(sensor)->getReportingMode();
+}
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index ec87c6e..2ed3d73 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -170,7 +170,7 @@
DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
- PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packagePath, 0);
+ PackageParser.ApkLite pkg = PackageParser.parseApkLite(packagePath, 0);
if (pkg == null) {
Slog.w(TAG, "Failed to parse package");
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 159ee66..3861cc1 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -32,7 +32,7 @@
<data android:mimeType="*/*" />
</intent-filter>
<intent-filter>
- <action android:name="android.intent.action.PICK_DIRECTORY" />
+ <action android:name="android.intent.action.OPEN_DOCUMENT_TREE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 9f76991..d0b6a1d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -24,7 +24,7 @@
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_PICK_DIRECTORY;
+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;
@@ -203,7 +203,7 @@
final String mimeType = getIntent().getType();
final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE);
SaveFragment.show(getFragmentManager(), mimeType, title);
- } else if (mState.action == ACTION_PICK_DIRECTORY) {
+ } else if (mState.action == ACTION_OPEN_TREE) {
PickFragment.show(getFragmentManager());
}
@@ -213,7 +213,7 @@
moreApps.setPackage(null);
RootsFragment.show(getFragmentManager(), moreApps);
} else if (mState.action == ACTION_OPEN || mState.action == ACTION_CREATE
- || mState.action == ACTION_PICK_DIRECTORY) {
+ || mState.action == ACTION_OPEN_TREE) {
RootsFragment.show(getFragmentManager(), null);
}
@@ -240,8 +240,8 @@
mState.action = ACTION_CREATE;
} else if (Intent.ACTION_GET_CONTENT.equals(action)) {
mState.action = ACTION_GET_CONTENT;
- } else if (Intent.ACTION_PICK_DIRECTORY.equals(action)) {
- mState.action = ACTION_PICK_DIRECTORY;
+ } else if (Intent.ACTION_OPEN_DOCUMENT_TREE.equals(action)) {
+ mState.action = ACTION_OPEN_TREE;
} else if (DocumentsContract.ACTION_MANAGE_ROOT.equals(action)) {
mState.action = ACTION_MANAGE;
}
@@ -441,7 +441,7 @@
actionBar.setIcon(new ColorDrawable());
if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT
- || mState.action == ACTION_PICK_DIRECTORY) {
+ || mState.action == ACTION_OPEN_TREE) {
actionBar.setTitle(R.string.title_open);
} else if (mState.action == ACTION_CREATE) {
actionBar.setTitle(R.string.title_save);
@@ -583,7 +583,7 @@
sortSize.setVisible(mState.showSize);
final boolean searchVisible;
- if (mState.action == ACTION_CREATE || mState.action == ACTION_PICK_DIRECTORY) {
+ if (mState.action == ACTION_CREATE || mState.action == ACTION_OPEN_TREE) {
createDir.setVisible(cwd != null && cwd.isCreateSupported());
searchVisible = false;
@@ -828,7 +828,7 @@
if (cwd == null) {
// No directory means recents
- if (mState.action == ACTION_CREATE || mState.action == ACTION_PICK_DIRECTORY) {
+ if (mState.action == ACTION_CREATE || mState.action == ACTION_OPEN_TREE) {
RecentsCreateFragment.show(fm);
} else {
DirectoryFragment.showRecentsOpen(fm, anim);
@@ -857,7 +857,7 @@
}
}
- if (mState.action == ACTION_PICK_DIRECTORY) {
+ if (mState.action == ACTION_OPEN_TREE) {
final PickFragment pick = PickFragment.get(fm);
if (pick != null) {
final CharSequence displayName = (mState.stack.size() <= 1) ? root.title
@@ -1021,7 +1021,7 @@
}
public void onPickRequested(DocumentInfo pickTarget) {
- final Uri viaUri = DocumentsContract.buildViaUri(pickTarget.authority,
+ final Uri viaUri = DocumentsContract.buildTreeDocumentUri(pickTarget.authority,
pickTarget.documentId);
new PickFinishTask(viaUri).executeOnExecutor(getCurrentExecutor());
}
@@ -1031,7 +1031,7 @@
final ContentValues values = new ContentValues();
final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack);
- if (mState.action == ACTION_CREATE || mState.action == ACTION_PICK_DIRECTORY) {
+ if (mState.action == ACTION_CREATE || mState.action == ACTION_OPEN_TREE) {
// Remember stack for last create
values.clear();
values.put(RecentColumns.KEY, mState.stack.buildKey());
@@ -1064,7 +1064,7 @@
if (mState.action == ACTION_GET_CONTENT) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- } else if (mState.action == ACTION_PICK_DIRECTORY) {
+ } else if (mState.action == ACTION_OPEN_TREE) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
@@ -1202,7 +1202,7 @@
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_PICK_DIRECTORY = 4;
+ public static final int ACTION_OPEN_TREE = 4;
public static final int ACTION_MANAGE = 5;
public static final int MODE_UNKNOWN = 0;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
index a9e488a1..5112c92 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
@@ -77,13 +77,15 @@
public void setPickTarget(DocumentInfo pickTarget, CharSequence displayName) {
mPickTarget = pickTarget;
- if (mPickTarget != null) {
- mContainer.setVisibility(View.VISIBLE);
- final Locale locale = getResources().getConfiguration().locale;
- final String raw = getString(R.string.menu_select).toUpperCase(locale);
- mPick.setText(TextUtils.expandTemplate(raw, displayName));
- } else {
- mContainer.setVisibility(View.GONE);
+ if (mContainer != null) {
+ if (mPickTarget != null) {
+ mContainer.setVisibility(View.VISIBLE);
+ final Locale locale = getResources().getConfiguration().locale;
+ final String raw = getString(R.string.menu_select).toUpperCase(locale);
+ mPick.setText(TextUtils.expandTemplate(raw, displayName));
+ } else {
+ mContainer.setVisibility(View.GONE);
+ }
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 933dbe0..caa7581 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -105,7 +105,7 @@
mRecentsRoot.rootId = null;
mRecentsRoot.icon = R.drawable.ic_root_recent;
mRecentsRoot.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE
- | Root.FLAG_SUPPORTS_DIR_SELECTION;
+ | Root.FLAG_SUPPORTS_IS_CHILD;
mRecentsRoot.title = mContext.getString(R.string.root_recent);
mRecentsRoot.availableBytes = -1;
@@ -350,7 +350,7 @@
final List<RootInfo> matching = Lists.newArrayList();
for (RootInfo root : roots) {
final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 0;
- final boolean supportsDir = (root.flags & Root.FLAG_SUPPORTS_DIR_SELECTION) != 0;
+ final boolean supportsIsChild = (root.flags & Root.FLAG_SUPPORTS_IS_CHILD) != 0;
final boolean advanced = (root.flags & Root.FLAG_ADVANCED) != 0;
final boolean localOnly = (root.flags & Root.FLAG_LOCAL_ONLY) != 0;
final boolean empty = (root.flags & Root.FLAG_EMPTY) != 0;
@@ -358,7 +358,7 @@
// Exclude read-only devices when creating
if (state.action == State.ACTION_CREATE && !supportsCreate) continue;
// Exclude roots that don't support directory picking
- if (state.action == State.ACTION_PICK_DIRECTORY && !supportsDir) continue;
+ if (state.action == State.ACTION_OPEN_TREE && !supportsIsChild) continue;
// Exclude advanced devices when not requested
if (!state.showAdvanced && advanced) continue;
// Exclude non-local devices when local only
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index d388ab7..9473eb9 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -145,7 +145,7 @@
final RootInfo root = new RootInfo();
root.rootId = rootId;
root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED
- | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_DIR_SELECTION;
+ | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD;
if (ROOT_ID_PRIMARY_EMULATED.equals(rootId)) {
root.title = getContext().getString(R.string.root_internal_storage);
} else {
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index 2917faa..006b1ee 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -56,7 +56,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/date_owner_info_margin"
android:layout_gravity="center_horizontal"
- android:textColor="#99ffffff"
+ android:textColor="#ccffffff"
android:textSize="@dimen/widget_label_font_size"
android:ellipsize="marquee"
android:singleLine="true" />
diff --git a/packages/Keyguard/res/values-af/strings.xml b/packages/Keyguard/res/values-af/strings.xml
index a046dc5..5811d14 100644
--- a/packages/Keyguard/res/values-af/strings.xml
+++ b/packages/Keyguard/res/values-af/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Om te ontsluit, druk Kieslys dan 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maksimum gesigontsluit-pogings oorskry"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Gelaai"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Laai, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Laai tans"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Koppel jou herlaaier."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Druk kieslys om te ontsluit."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Netwerk gesluit"</string>
diff --git a/packages/Keyguard/res/values-am/strings.xml b/packages/Keyguard/res/values-am/strings.xml
index 0bb7993..a630dee 100644
--- a/packages/Keyguard/res/values-am/strings.xml
+++ b/packages/Keyguard/res/values-am/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"ለመክፈት፣ምናሌ ተጫን ከዛ 0"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"የመጨረሻውን የገጽ ክፈት ሙከራዎችን አልፏል"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"ባትሪ ሞልቷል"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"ባትሪ በመሙላት ላይ፣ <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"ኃይል በመሙላት ላይ"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"የኃይል መሙያዎን ይሰኩ።"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"ለመክፈት ምናሌውን ይጫኑ።"</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"አውታረ መረብ ተቆልፏል"</string>
diff --git a/packages/Keyguard/res/values-ar/strings.xml b/packages/Keyguard/res/values-ar/strings.xml
index eac3216..48a5fca 100644
--- a/packages/Keyguard/res/values-ar/strings.xml
+++ b/packages/Keyguard/res/values-ar/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"لإلغاء التأمين، اضغط على \"القائمة\" ثم على 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"تم تجاوز الحد الأقصى لعدد محاولات تأمين الجهاز بالوجه"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"تم الشحن"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"جارٍ الشحن، <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"جارٍ الشحن"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"توصيل جهاز الشحن."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"اضغط على \"القائمة\" لإلغاء القفل."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"الشبكة مؤمّنة"</string>
diff --git a/packages/Keyguard/res/values-bg/strings.xml b/packages/Keyguard/res/values-bg/strings.xml
index ad4285a..e8d5533 100644
--- a/packages/Keyguard/res/values-bg/strings.xml
+++ b/packages/Keyguard/res/values-bg/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"За да отключите, натиснете „Меню“ и после 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Максималният брой опити за отключване с лице е надвишен"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Заредена"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Зарежда се, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Зарежда се"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Свържете зарядното си устройство."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Натиснете иконата за меню, за да отключите."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Мрежата е заключена"</string>
diff --git a/packages/Keyguard/res/values-ca/strings.xml b/packages/Keyguard/res/values-ca/strings.xml
index 7e40709..d23d487 100644
--- a/packages/Keyguard/res/values-ca/strings.xml
+++ b/packages/Keyguard/res/values-ca/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Per desbloquejar-lo, premeu Menú i després 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"S\'ha superat el nombre màxim d\'intents de desbloqueig facial"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Carregada"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"S\'està carregant, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Carregant"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Connecta el carregador."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Prem Menú per desbloquejar."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Xarxa bloquejada"</string>
diff --git a/packages/Keyguard/res/values-cs/strings.xml b/packages/Keyguard/res/values-cs/strings.xml
index 53cc707..5df0508 100644
--- a/packages/Keyguard/res/values-cs/strings.xml
+++ b/packages/Keyguard/res/values-cs/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Chcete-li telefon odemknout, stiskněte Menu a poté 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Překročili jste maximální povolený počet pokusů o odemknutí obličejem."</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Nabito"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Nabíjení, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Nabíjení"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Připojte dobíjecí zařízení."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Telefon odemknete stisknutím tlačítka Menu."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Síť je blokována"</string>
diff --git a/packages/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml
index cf1aad9..85ebf4b 100644
--- a/packages/Keyguard/res/values-da/strings.xml
+++ b/packages/Keyguard/res/values-da/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Tryk på Menu og dernæst på 0 for at låse op."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Det maksimale antal forsøg på at bruge Ansigtslås er overskredet"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Opladet"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Oplader, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Oplader"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Tilslut din oplader."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Tryk på Menu for at låse op."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Netværket er låst"</string>
diff --git a/packages/Keyguard/res/values-de/strings.xml b/packages/Keyguard/res/values-de/strings.xml
index 14df237..bf88124 100644
--- a/packages/Keyguard/res/values-de/strings.xml
+++ b/packages/Keyguard/res/values-de/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Drücken Sie zum Entsperren die Menütaste und dann auf \"0\"."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Die maximal zulässige Anzahl an Face Unlock-Versuchen wurde überschritten."</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Aufgeladen"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Akku wird aufgeladen (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Wird aufgeladen"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Bitte Ladegerät anschließen"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Zum Entsperren die Menütaste drücken"</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Netzwerk gesperrt"</string>
diff --git a/packages/Keyguard/res/values-el/strings.xml b/packages/Keyguard/res/values-el/strings.xml
index 63d8409..e928662 100644
--- a/packages/Keyguard/res/values-el/strings.xml
+++ b/packages/Keyguard/res/values-el/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Για ξεκλείδωμα, πατήστε το πλήκτρο Menu και, στη συνέχεια, το πλήκτρο 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Έγινε υπέρβαση του μέγιστου αριθμού προσπαθειών Face Unlock"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Φορτίστηκε"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Φόρτιση, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Φόρτιση"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Συνδέστε τον φορτιστή."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Πατήστε \"Μενού\" για ξεκλείδωμα."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Το δίκτυο κλειδώθηκε"</string>
diff --git a/packages/Keyguard/res/values-en-rGB/strings.xml b/packages/Keyguard/res/values-en-rGB/strings.xml
index ecc850d..962c80d 100644
--- a/packages/Keyguard/res/values-en-rGB/strings.xml
+++ b/packages/Keyguard/res/values-en-rGB/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"To unlock, press Menu, then 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maximum Face Unlock attempts exceeded"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Charged"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Charging, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Charging"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Connect your charger."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Press Menu to unlock."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Network locked"</string>
diff --git a/packages/Keyguard/res/values-en-rIN/strings.xml b/packages/Keyguard/res/values-en-rIN/strings.xml
index ecc850d..962c80d 100644
--- a/packages/Keyguard/res/values-en-rIN/strings.xml
+++ b/packages/Keyguard/res/values-en-rIN/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"To unlock, press Menu, then 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maximum Face Unlock attempts exceeded"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Charged"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Charging, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Charging"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Connect your charger."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Press Menu to unlock."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Network locked"</string>
diff --git a/packages/Keyguard/res/values-es-rUS/strings.xml b/packages/Keyguard/res/values-es-rUS/strings.xml
index c6d63ba..47288a1 100644
--- a/packages/Keyguard/res/values-es-rUS/strings.xml
+++ b/packages/Keyguard/res/values-es-rUS/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, presiona el menú y luego 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se superó el máximo de intentos permitido para el desbloqueo facial del dispositivo."</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Cargada"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Cargando"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Conecta tu cargador."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Presiona Menú para desbloquear."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Bloqueada para la red"</string>
diff --git a/packages/Keyguard/res/values-es/strings.xml b/packages/Keyguard/res/values-es/strings.xml
index 8a78399..1bf3b0c 100644
--- a/packages/Keyguard/res/values-es/strings.xml
+++ b/packages/Keyguard/res/values-es/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear el teléfono, pulsa la tecla de menú y, a continuación, pulsa 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Se ha superado el número máximo de intentos de desbloqueo facial."</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Cargada"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Cargando"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Conecta el cargador."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Ve al menú para desbloquear la pantalla."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Bloqueada para la red"</string>
diff --git a/packages/Keyguard/res/values-et-rEE/strings.xml b/packages/Keyguard/res/values-et-rEE/strings.xml
index b837f01..ad43c08 100644
--- a/packages/Keyguard/res/values-et-rEE/strings.xml
+++ b/packages/Keyguard/res/values-et-rEE/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Avamiseks vajutage menüüklahvi, seejärel klahvi 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maksimaalne teenusega Face Unlock avamise katsete arv on ületatud"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Laetud"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Laadimine, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Laadimine"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Ühendage laadija."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Avamiseks vajutage menüüklahvi."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Võrk on suletud"</string>
diff --git a/packages/Keyguard/res/values-fa/strings.xml b/packages/Keyguard/res/values-fa/strings.xml
index 5d1c487..fe9652c 100644
--- a/packages/Keyguard/res/values-fa/strings.xml
+++ b/packages/Keyguard/res/values-fa/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"برای بازگشایی قفل، منو را فشار دهید و سپس 0 را فشار دهید."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"دفعات تلاش برای Face Unlock از حداکثر مجاز بیشتر شد"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"شارژ شد"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"شارژ، <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"شارژ کردن"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"شارژر خود را وصل کنید."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"برای بازگشایی قفل روی منو فشار دهید."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"شبکه قفل شد"</string>
diff --git a/packages/Keyguard/res/values-fi/strings.xml b/packages/Keyguard/res/values-fi/strings.xml
index bdf6677..4a18898 100644
--- a/packages/Keyguard/res/values-fi/strings.xml
+++ b/packages/Keyguard/res/values-fi/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Poista lukitus painamalla Valikko-painiketta ja 0-näppäintä."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Face Unlock -yrityksiä tehty suurin sallittu määrä."</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Täynnä"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Ladataan (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Ladataan"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Kytke laturi."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Poista lukitus painamalla Valikko-painiketta."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Verkko lukittu"</string>
diff --git a/packages/Keyguard/res/values-fr-rCA/strings.xml b/packages/Keyguard/res/values-fr-rCA/strings.xml
index e77927c..a3960bf 100644
--- a/packages/Keyguard/res/values-fr-rCA/strings.xml
+++ b/packages/Keyguard/res/values-fr-rCA/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Pour déverrouiller le téléphone, appuyez sur \"Menu\", puis sur 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Nombre maximal autorisé de tentatives Face Unlock atteint."</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Chargé"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"En charge (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Charge en cours..."</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Branchez votre chargeur."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Appuyez sur \"Menu\" pour déverrouiller l\'appareil."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Réseau verrouillé"</string>
diff --git a/packages/Keyguard/res/values-fr/strings.xml b/packages/Keyguard/res/values-fr/strings.xml
index 41be1eb..6416e53 100644
--- a/packages/Keyguard/res/values-fr/strings.xml
+++ b/packages/Keyguard/res/values-fr/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Pour déverrouiller le clavier, appuyez sur \"Menu\" puis sur 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Nombre maximal autorisé de tentatives Face Unlock atteint."</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Chargé"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"En charge (<xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Batterie en charge…"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Branchez votre chargeur."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Appuyez sur \"Menu\" pour déverrouiller l\'appareil."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Réseau verrouillé"</string>
diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml
index c963beb..f197138 100644
--- a/packages/Keyguard/res/values-hi/strings.xml
+++ b/packages/Keyguard/res/values-hi/strings.xml
@@ -31,8 +31,8 @@
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"गलत पिन कोड."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"अनलॉक करने के लिए, मेनू दबाएं और फिर 0 दबाएं."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"फेस अनलॉक के अधिकतम प्रयासों की सीमा पार हो गई"</string>
- <string name="keyguard_charged" msgid="3272223906073492454">"चार्ज हो गई"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"चार्ज हो रही है, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"चार्ज हो गई है"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"चार्ज हो रहा है"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"अपना चार्जर कनेक्ट करें."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"अनलॉक करने के लिए मेनू दबाएं."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"नेटवर्क लॉक किया गया"</string>
diff --git a/packages/Keyguard/res/values-hr/strings.xml b/packages/Keyguard/res/values-hr/strings.xml
index 6bbdd51..5c6a467 100644
--- a/packages/Keyguard/res/values-hr/strings.xml
+++ b/packages/Keyguard/res/values-hr/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Za otključavanje pritisnite Izbornik pa 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Premašen je maksimalni broj Otključavanja licem"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Napunjeno"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Puni se, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Punjenje"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Priključite punjač."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Pritisnite Izbornik za otključavanje."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Mreža je zaključana"</string>
diff --git a/packages/Keyguard/res/values-hu/strings.xml b/packages/Keyguard/res/values-hu/strings.xml
index 9706874..93b9948 100644
--- a/packages/Keyguard/res/values-hu/strings.xml
+++ b/packages/Keyguard/res/values-hu/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"A feloldáshoz nyomja meg a Menü, majd a 0 gombot."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Elérte az arcalapú feloldási kísérletek maximális számát"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Feltöltve"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Töltés (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Töltés"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Csatlakoztassa a töltőt."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"A feloldáshoz nyomja meg a Menü gombot."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"A hálózat lezárva"</string>
diff --git a/packages/Keyguard/res/values-hy-rAM/strings.xml b/packages/Keyguard/res/values-hy-rAM/strings.xml
index 60c626d..0a4c8e0 100644
--- a/packages/Keyguard/res/values-hy-rAM/strings.xml
+++ b/packages/Keyguard/res/values-hy-rAM/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Ապակողպման համար սեղմեք Ցանկ, ապա 0:"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Առավելագույն Դեմքով ապակողպման փորձերը գերազանցված են"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Լիցքավորված է"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Լիցքավորում, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Լիցքավորում"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Միացրեք ձեր լիցքավորիչը:"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Ապակողպելու համար սեղմեք Ցանկը:"</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Ցանցը կողպված է"</string>
diff --git a/packages/Keyguard/res/values-in/strings.xml b/packages/Keyguard/res/values-in/strings.xml
index 9ea5a29..343c320 100644
--- a/packages/Keyguard/res/values-in/strings.xml
+++ b/packages/Keyguard/res/values-in/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Untuk membuka, tekan Menu lalu 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Percobaan Face Unlock melebihi batas maksimum"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Terisi"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Mengisi baterai, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Mengisi daya"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Hubungkan pengisi daya."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Tekan Menu untuk membuka."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Jaringan terkunci"</string>
diff --git a/packages/Keyguard/res/values-it/strings.xml b/packages/Keyguard/res/values-it/strings.xml
index 2a481e6..6c7cbfe 100644
--- a/packages/Keyguard/res/values-it/strings.xml
+++ b/packages/Keyguard/res/values-it/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Per sbloccare, premi Menu, poi 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Numero massimo di tentativi di Sblocco col sorriso superato"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Carico"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"In carica (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"In carica"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Collega il caricabatterie."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Premi Menu per sbloccare."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Rete bloccata"</string>
diff --git a/packages/Keyguard/res/values-iw/strings.xml b/packages/Keyguard/res/values-iw/strings.xml
index a6a3192..7f73b5a 100644
--- a/packages/Keyguard/res/values-iw/strings.xml
+++ b/packages/Keyguard/res/values-iw/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"כדי לבטל את הנעילה, לחץ על \'תפריט\' ולאחר מכן על 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"חרגת ממספר הניסיונות המרבי של זיהוי פנים"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"טעון"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"טוען, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"טוען"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"חבר את המטען."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"לחץ על \'תפריט\' כדי לבטל את הנעילה."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"רשת נעולה"</string>
diff --git a/packages/Keyguard/res/values-ja/strings.xml b/packages/Keyguard/res/values-ja/strings.xml
index b683a9d..3b7ea6a 100644
--- a/packages/Keyguard/res/values-ja/strings.xml
+++ b/packages/Keyguard/res/values-ja/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"MENU、0キーでロック解除"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"フェイスアンロックの最大試行回数を超えました"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"充電完了"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"充電中: <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"充電中"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"充電してください。"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"メニューからロックを解除できます。"</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"ネットワークがロックされました"</string>
diff --git a/packages/Keyguard/res/values-ka-rGE/strings.xml b/packages/Keyguard/res/values-ka-rGE/strings.xml
index 4414096..36a2d79 100644
--- a/packages/Keyguard/res/values-ka-rGE/strings.xml
+++ b/packages/Keyguard/res/values-ka-rGE/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"განბლოკვისათვის დააჭირეთ მენიუს და შემდეგ 0-ს."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"სახის ამოცნობით განბლოკვის მცდელობამ დაშვებულ რაოდენობას გადააჭარბა"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"დამუხტულია"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"მიმდინარეობს დამუხტვა (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"მიმდინარეობს დატენვა"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"შეაერთეთ დამტენი."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"განბლოკვისთვის დააჭირეთ მენიუს."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"ქსელი ჩაკეტილია"</string>
diff --git a/packages/Keyguard/res/values-km-rKH/strings.xml b/packages/Keyguard/res/values-km-rKH/strings.xml
index 18b59f1..c26b1b4 100644
--- a/packages/Keyguard/res/values-km-rKH/strings.xml
+++ b/packages/Keyguard/res/values-km-rKH/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"ដើម្បីដោះសោ ចុចម៉ឺនុយ បន្ទាប់មក 0 ។"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"បានលើសការព្យាយាមដោះសោតាមទម្រង់មុខ"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"បានបញ្ចូលពេញ"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"បញ្ចូលថ្ម <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"កំពុងបញ្ចូលថ្ម"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"ភ្ជាប់ឧបករណ៍បញ្ចូលថ្ម។"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"ចុចម៉ឺនុយ ដើម្បីដោះសោ។"</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"បណ្ដាញជាប់សោ"</string>
diff --git a/packages/Keyguard/res/values-ko/strings.xml b/packages/Keyguard/res/values-ko/strings.xml
index cde2b1c..994c532 100644
--- a/packages/Keyguard/res/values-ko/strings.xml
+++ b/packages/Keyguard/res/values-ko/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"잠금해제하려면 메뉴를 누른 다음 0을 누릅니다."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"얼굴 인식 잠금해제 최대 시도 횟수를 초과했습니다."</string>
<string name="keyguard_charged" msgid="3272223906073492454">"충전됨"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"충전 중(<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"충전 중"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"충전기를 연결하세요."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"잠금해제하려면 메뉴를 누르세요."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"네트워크 잠김"</string>
diff --git a/packages/Keyguard/res/values-lo-rLA/strings.xml b/packages/Keyguard/res/values-lo-rLA/strings.xml
index 0571768..cff4cd5 100644
--- a/packages/Keyguard/res/values-lo-rLA/strings.xml
+++ b/packages/Keyguard/res/values-lo-rLA/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"ເພື່ອປົດລັອກ, ໃຫ້ກົດເມນູ ແລ້ວກົດ 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"ຄວາມພະຍາຍາມປົດລັອກດ້ວຍໜ້ານັ້ນ ເກີນຈຳນວນທີ່ກຳນົດແລ້ວ"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"ສາກເຕັມແລ້ວ"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"ກຳລັງສາກ, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"ກຳລັງສາກໄຟ"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"ເຊື່ອມຕໍ່ອຸປະກອນສາກຂອງທ່ານ."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"ກົດເມນູເພື່ອປົດລັອກ."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"ເຄືອຂ່າຍຖືກລັອກ"</string>
diff --git a/packages/Keyguard/res/values-lt/strings.xml b/packages/Keyguard/res/values-lt/strings.xml
index 0fd6605..e965076 100644
--- a/packages/Keyguard/res/values-lt/strings.xml
+++ b/packages/Keyguard/res/values-lt/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Jei norite atrakinti, paspauskite „Meniu“ ir 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Viršijote maksimalų atrakinimo pagal veidą bandymų skaičių"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Įkrauta"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Įkraunama, <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Kraunama"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Prijunkite įkroviklį."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Jei norite atrakinti, paspauskite „Meniu“."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Tinklas užrakintas"</string>
diff --git a/packages/Keyguard/res/values-lv/strings.xml b/packages/Keyguard/res/values-lv/strings.xml
index 2bcde1d..144fe88 100644
--- a/packages/Keyguard/res/values-lv/strings.xml
+++ b/packages/Keyguard/res/values-lv/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Lai atbloķētu, nospiediet Izvēlne, pēc tam 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Ir pārsniegts maksimālais Autorizācijas pēc sejas mēģinājumu skaits."</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Uzlādēts"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Notiek uzlāde (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Notiek uzlāde"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Pievienojiet uzlādes ierīci."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Lai atbloķētu, nospiediet vienumu Izvēlne."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Tīkls ir bloķēts."</string>
diff --git a/packages/Keyguard/res/values-mn-rMN/strings.xml b/packages/Keyguard/res/values-mn-rMN/strings.xml
index 7bb819d..200e104 100644
--- a/packages/Keyguard/res/values-mn-rMN/strings.xml
+++ b/packages/Keyguard/res/values-mn-rMN/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Тайлах бол Цэсийг дараад 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Нүүрээр түгжээ тайлах оролдлогын тоо дээд хэмжээнээс хэтэрсэн"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Цэнэглэгдэв"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Цэнэглэж байна, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Цэнэглэж байна"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Цэнэглэгчээ холбоно уу."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Тайлх бол цэсийг дарна уу."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Сүлжээ түгжигдсэн"</string>
diff --git a/packages/Keyguard/res/values-ms-rMY/strings.xml b/packages/Keyguard/res/values-ms-rMY/strings.xml
index b4c1b46..0592b34 100644
--- a/packages/Keyguard/res/values-ms-rMY/strings.xml
+++ b/packages/Keyguard/res/values-ms-rMY/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Untuk membuka kunci, tekan Menu, kemudian 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Telah melepasi had cubaan Buka Kunci Wajah"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Sudah dicas"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Mengecas, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Mengecas"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Sambungkan pengecas anda."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Tekan Menu untuk membuka kunci."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Rangkaian dikunci"</string>
diff --git a/packages/Keyguard/res/values-nb/strings.xml b/packages/Keyguard/res/values-nb/strings.xml
index 801e03d..44b9641 100644
--- a/packages/Keyguard/res/values-nb/strings.xml
+++ b/packages/Keyguard/res/values-nb/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"For å låse opp, trykk på menyknappen og deretter 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Du har overskredet grensen for opplåsingsforsøk med Ansiktslås"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Oppladet"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Lader: <xliff:g id="NUMBER">%d</xliff:g> <xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Lader"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Koble til laderen."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Trykk på Meny for å låse opp."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Nettverk låst"</string>
diff --git a/packages/Keyguard/res/values-nl/strings.xml b/packages/Keyguard/res/values-nl/strings.xml
index 195f950..5006f49 100644
--- a/packages/Keyguard/res/values-nl/strings.xml
+++ b/packages/Keyguard/res/values-nl/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Druk op \'Menu\' en vervolgens op 0 om te ontgrendelen."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maximaal aantal pogingen voor Ontgrendelen via gezichtsherkenning overschreden"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Opgeladen"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Opladen, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Opladen"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Sluit de oplader aan."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Druk op \'Menu\' om te ontgrendelen."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Netwerk vergrendeld"</string>
diff --git a/packages/Keyguard/res/values-pl/strings.xml b/packages/Keyguard/res/values-pl/strings.xml
index 165b2c4..8e22a5a 100644
--- a/packages/Keyguard/res/values-pl/strings.xml
+++ b/packages/Keyguard/res/values-pl/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Aby odblokować, naciśnij Menu, a następnie 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Przekroczono maksymalną liczbę prób rozpoznania twarzy."</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Naładowana"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Ładowanie (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Ładuje się"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Podłącz ładowarkę."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Naciśnij Menu, by odblokować."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Zablokowana sieć"</string>
diff --git a/packages/Keyguard/res/values-pt-rPT/strings.xml b/packages/Keyguard/res/values-pt-rPT/strings.xml
index 332a943..443f4c2 100644
--- a/packages/Keyguard/res/values-pt-rPT/strings.xml
+++ b/packages/Keyguard/res/values-pt-rPT/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, prima Menu e, em seguida, 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Excedido o n.º máximo de tentativas de Desbloqueio Através do Rosto"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Carregado"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"A carregar, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"A carregar"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Ligue o carregador."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Prima Menu para desbloquear."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Rede bloqueada"</string>
diff --git a/packages/Keyguard/res/values-pt/strings.xml b/packages/Keyguard/res/values-pt/strings.xml
index a97b1b6..f7d6c1b 100644
--- a/packages/Keyguard/res/values-pt/strings.xml
+++ b/packages/Keyguard/res/values-pt/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, pressione Menu e, em seguida, 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"O número máximo de tentativas de Desbloqueio por reconhecimento facial foi excedido"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Carregado"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Carregando, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Carregando"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Conecte seu carregador."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Pressione \"Menu\" para desbloquear."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Rede bloqueada"</string>
diff --git a/packages/Keyguard/res/values-rm/strings.xml b/packages/Keyguard/res/values-rm/strings.xml
index 4d71f27..9ce72a4 100644
--- a/packages/Keyguard/res/values-rm/strings.xml
+++ b/packages/Keyguard/res/values-rm/strings.xml
@@ -43,7 +43,7 @@
<skip />
<!-- no translation found for keyguard_charged (3272223906073492454) -->
<skip />
- <!-- no translation found for keyguard_plugged_in (8117572000639998388) -->
+ <!-- no translation found for keyguard_plugged_in (9087497435553252863) -->
<skip />
<!-- no translation found for keyguard_low_battery (8143808018719173859) -->
<skip />
diff --git a/packages/Keyguard/res/values-ro/strings.xml b/packages/Keyguard/res/values-ro/strings.xml
index 58bc337..2ab07b4 100644
--- a/packages/Keyguard/res/values-ro/strings.xml
+++ b/packages/Keyguard/res/values-ro/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Pentru a debloca, apăsaţi Meniu, apoi 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"S-a depăşit numărul maxim de încercări pentru Deblocare facială"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Încărcată"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Se încarcă, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Se încarcă"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Conectați încărcătorul."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Apăsați pe Meniu pentru a debloca."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Rețea blocată"</string>
diff --git a/packages/Keyguard/res/values-ru/strings.xml b/packages/Keyguard/res/values-ru/strings.xml
index 866abc0..56e9e54 100644
--- a/packages/Keyguard/res/values-ru/strings.xml
+++ b/packages/Keyguard/res/values-ru/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Для разблокировки нажмите \"Меню\", а затем 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Все попытки войти с помощью Фейсконтроля использованы"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Батарея заряжена"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Идет зарядка (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Зарядка батареи"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Подключите зарядное устройство."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Для разблокировки нажмите \"Меню\"."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Сеть заблокирована"</string>
diff --git a/packages/Keyguard/res/values-sk/strings.xml b/packages/Keyguard/res/values-sk/strings.xml
index 45e4288..de18f14 100644
--- a/packages/Keyguard/res/values-sk/strings.xml
+++ b/packages/Keyguard/res/values-sk/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Ak chcete telefón odomknúť, stlačte Menu a následne 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Prekročili ste maximálny povolený počet pokusov o odomknutie tvárou"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Batéria je nabitá"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Nabíjanie, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Nabíja sa"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Pripojte nabíjačku."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Telefón odomknete stlačením tlačidla Menu."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Sieť je zablokovaná"</string>
diff --git a/packages/Keyguard/res/values-sl/strings.xml b/packages/Keyguard/res/values-sl/strings.xml
index cf72e47..981fb44 100644
--- a/packages/Keyguard/res/values-sl/strings.xml
+++ b/packages/Keyguard/res/values-sl/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Če želite telefon odkleniti, pritisnite meni in nato 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Presegli ste dovoljeno število poskusov odklepanja z obrazom"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Napolnjeno"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Polnjenje, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Polnjenje"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Priključite napajalnik."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Če želite odkleniti, pritisnite meni."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Omrežje je zaklenjeno"</string>
diff --git a/packages/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
index bd08eae..b944237 100644
--- a/packages/Keyguard/res/values-sr/strings.xml
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Да бисте откључали, притисните „Мени“, а затим 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Премашен је највећи дозвољени број покушаја Откључавања лицем"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Напуњено"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Пуњење, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Пуњење"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Повежите пуњач."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Притисните Мени да бисте откључали."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Мрежа је закључана"</string>
@@ -128,8 +128,8 @@
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте PIN неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Унели сте лозинку неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Покушали сте да откључате таблет неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. Након још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја таблет ће бити враћен на подразумевана фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Покушали сте да откључате телефон неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја телефон ће бити враћен на подразумевана фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Покушали сте да откључате таблет неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. Након још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја таблет ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Покушали сте да откључате телефон неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја телефон ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Покушали сте да откључате таблет неисправно <xliff:g id="NUMBER">%d</xliff:g> пута. Таблет ће сада бити враћен на подразумевана фабричка подешавања."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Покушали сте да откључате телефон неисправно <xliff:g id="NUMBER">%d</xliff:g> пута. Телефон ће сада бити враћен на подразумевана фабричка подешавања."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
diff --git a/packages/Keyguard/res/values-sv/strings.xml b/packages/Keyguard/res/values-sv/strings.xml
index 1214100..a3c7295 100644
--- a/packages/Keyguard/res/values-sv/strings.xml
+++ b/packages/Keyguard/res/values-sv/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Tryck på Menu och sedan på 0 om du vill låsa upp."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Du har försökt låsa upp med Ansiktslås för många gånger"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Batteriet har laddats"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Laddar, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Debitering"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Anslut din laddare."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Tryck på Meny om du vill låsa upp."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Nätverk låst"</string>
diff --git a/packages/Keyguard/res/values-sw/strings.xml b/packages/Keyguard/res/values-sw/strings.xml
index fc1ce17..ca2ce47 100644
--- a/packages/Keyguard/res/values-sw/strings.xml
+++ b/packages/Keyguard/res/values-sw/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Ili kufungua, bofya Menyu kisha 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Majaribio ya Juu ya Kufungua Uso yamezidishwa"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Betri imejaa"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Inachaji, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Inachaji"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Unganisha chaja yako."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Bonyeza Menyu ili kufungua."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Mtandao umefungwa"</string>
diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml
index e9e9b89..69bf44f 100644
--- a/packages/Keyguard/res/values-sw600dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp/dimens.xml
@@ -63,14 +63,11 @@
<dimen name="keyguard_muliuser_selector_margin">12dp</dimen>
<!-- Overload default clock widget parameters -->
- <dimen name="widget_big_font_size">96dp</dimen>
+ <dimen name="widget_big_font_size">120dp</dimen>
<dimen name="widget_label_font_size">16sp</dimen>
- <dimen name="bottom_text_spacing_digital">-8dp</dimen>
+ <dimen name="bottom_text_spacing_digital">-16dp</dimen>
<!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
Should be 0 on devices with plenty of room (e.g. tablets) -->
<dimen name="eca_overlap">0dip</dimen>
-
- <!-- The vertical margin between the date and the owner info. -->
- <dimen name="date_owner_info_margin">4dp</dimen>
</resources>
diff --git a/packages/Keyguard/res/values-th/strings.xml b/packages/Keyguard/res/values-th/strings.xml
index 34d97c2..368e004 100644
--- a/packages/Keyguard/res/values-th/strings.xml
+++ b/packages/Keyguard/res/values-th/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"หากต้องการปลดล็อก กด เมนู ตามด้วย 0"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"มีความพยายามที่จะใช้ Face Unlock เกินขีดจำกัด"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"ชาร์จแล้ว"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"กำลังชาร์จ, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"กำลังชาร์จ"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"เสียบที่ชาร์จของคุณ"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"กด \"เมนู\" เพื่อปลดล็อก"</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"เครือข่ายล็อก"</string>
diff --git a/packages/Keyguard/res/values-tl/strings.xml b/packages/Keyguard/res/values-tl/strings.xml
index 9d97d22..5a1090a 100644
--- a/packages/Keyguard/res/values-tl/strings.xml
+++ b/packages/Keyguard/res/values-tl/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Upang i-unlock, pindutin ang Menu pagkatapos ay 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Nalagpasan na ang maximum na mga pagtatangka sa Face Unlock"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Na-charge"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Nagcha-charge, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Nagtsa-charge"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Ikonekta ang iyong charger."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Pindutin ang Menu upang i-unlock."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Naka-lock ang network"</string>
diff --git a/packages/Keyguard/res/values-tr/strings.xml b/packages/Keyguard/res/values-tr/strings.xml
index 1d8b982..e2c1892 100644
--- a/packages/Keyguard/res/values-tr/strings.xml
+++ b/packages/Keyguard/res/values-tr/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Kilidi açmak için önce Menü\'ye, sonra 0\'a basın."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Yüz Tanıma Kilidi için maksimum deneme sayısı aşıldı"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Şarj oldu"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Şarj oluyor, <xliff:g id="PERCENT">%%</xliff:g><xliff:g id="NUMBER">%d</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Şarj oluyor"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Şarj cihazınızı takın."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Kilidi açmak için Menü\'ye basın."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Ağ kilitli"</string>
diff --git a/packages/Keyguard/res/values-uk/strings.xml b/packages/Keyguard/res/values-uk/strings.xml
index 16cf6cf..519aa4d 100644
--- a/packages/Keyguard/res/values-uk/strings.xml
+++ b/packages/Keyguard/res/values-uk/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Щоб розбл., натисн. меню та 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Перевищено максимальну кількість спроб розблокування за допомогою функції \"Фейсконтроль\""</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Заряджено"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Заряджається, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Заряджається"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Підключіть зарядний пристрій."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Натисніть Меню, щоб розблокувати."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Мережу заблоковано"</string>
diff --git a/packages/Keyguard/res/values-vi/strings.xml b/packages/Keyguard/res/values-vi/strings.xml
index 00693aa5..58bda92 100644
--- a/packages/Keyguard/res/values-vi/strings.xml
+++ b/packages/Keyguard/res/values-vi/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Để mở khóa, hãy nhấn vào Trình đơn sau đó nhấn 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Đã vượt quá số lần Mở khóa bằng khuôn mặt tối đa"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Pin đầy"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Đang sạc, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Đang sạc"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Kết nối bộ sạc của bạn."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Nhấn vào Trình đơn để mở khóa."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Mạng đã bị khóa"</string>
diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml
index 1c014c3..09f521a 100644
--- a/packages/Keyguard/res/values-zh-rCN/strings.xml
+++ b/packages/Keyguard/res/values-zh-rCN/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"要解锁,请先按 MENU 再按 0。"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"已超过“人脸解锁”尝试次数上限"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"充电完成"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"正在充电 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"正在充电"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"请连接充电器。"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"按“菜单”键解锁。"</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"网络已锁定"</string>
diff --git a/packages/Keyguard/res/values-zh-rHK/strings.xml b/packages/Keyguard/res/values-zh-rHK/strings.xml
index 1b621d6..280dea3 100644
--- a/packages/Keyguard/res/values-zh-rHK/strings.xml
+++ b/packages/Keyguard/res/values-zh-rHK/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"如要解鎖,請按選單鍵,然後按 0。"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"已超過臉容解鎖嘗試次數上限"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"充電完成"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"充電中 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"充電中"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"請連接充電器。"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"按選單鍵解鎖。"</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"網絡已鎖定"</string>
diff --git a/packages/Keyguard/res/values-zh-rTW/strings.xml b/packages/Keyguard/res/values-zh-rTW/strings.xml
index 6e632ef..349282c 100644
--- a/packages/Keyguard/res/values-zh-rTW/strings.xml
+++ b/packages/Keyguard/res/values-zh-rTW/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"如要解鎖,請按 Menu 鍵,然後按 0。"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"已超過人臉解鎖嘗試次數上限"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"充電完成"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"充電中 (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"充電中"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"連接充電器。"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"按選單鍵解鎖。"</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"網路已鎖定"</string>
diff --git a/packages/Keyguard/res/values-zu/strings.xml b/packages/Keyguard/res/values-zu/strings.xml
index 95d3474..c69bc18 100644
--- a/packages/Keyguard/res/values-zu/strings.xml
+++ b/packages/Keyguard/res/values-zu/strings.xml
@@ -32,7 +32,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Ukuvula, chofoza Menyu bese 0."</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Ukuzama Kokuvula Ubuso Okuningi kudluliwe"</string>
<string name="keyguard_charged" msgid="3272223906073492454">"Kushajiwe"</string>
- <string name="keyguard_plugged_in" msgid="8117572000639998388">"Iyashaja, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Iyashaja"</string>
<string name="keyguard_low_battery" msgid="8143808018719173859">"Xhuma ishaja yakho."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Chofoza imenyu ukuze uvule."</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"Inethiwekhi ikhiyiwe"</string>
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index f971522..4b113ff 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -155,15 +155,15 @@
<dimen name="eca_overlap">-10dip</dimen>
<!-- Default clock parameters -->
- <dimen name="bottom_text_spacing_digital">-6dp</dimen>
+ <dimen name="bottom_text_spacing_digital">-10dp</dimen>
<dimen name="label_font_size">14dp</dimen>
- <dimen name="widget_label_font_size">14sp</dimen>
- <dimen name="widget_big_font_size">68dp</dimen>
+ <dimen name="widget_label_font_size">16sp</dimen>
+ <dimen name="widget_big_font_size">96dp</dimen>
<dimen name="big_font_size">120dp</dimen>
<!-- The y translation to apply at the start in appear animations. -->
<dimen name="appear_y_translation_start">32dp</dimen>
<!-- The vertical margin between the date and the owner info. -->
- <dimen name="date_owner_info_margin">2dp</dimen>
+ <dimen name="date_owner_info_margin">10dp</dimen>
</resources>
diff --git a/packages/Keyguard/res/values/donottranslate.xml b/packages/Keyguard/res/values/donottranslate.xml
index 16f5a3e..78636db 100644
--- a/packages/Keyguard/res/values/donottranslate.xml
+++ b/packages/Keyguard/res/values/donottranslate.xml
@@ -16,7 +16,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Skeleton string format for displaying the date. -->
- <string name="abbrev_wday_month_day_no_year">EEEMMMMd</string>
+ <string name="abbrev_wday_month_day_no_year">EEEEMMMMd</string>
<!-- Skeleton string format for displaying the time in 12-hour format. -->
<string name="clock_12hr_format">hm</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
index 3f6ced6..bc159cb 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimpleHostView.java
@@ -25,6 +25,7 @@
public KeyguardSimpleHostView(Context context, AttributeSet attrs) {
super(context, attrs);
+ KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateCallback);
}
@Override
@@ -62,4 +63,10 @@
// TODO Auto-generated method stub
}
+ private KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onUserSwitchComplete(int userId) {
+ getSecurityContainer().showPrimarySecurityScreen(false /* turning off */);
+ }
+ };
}
diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk
index 9e7b969..96592b4 100644
--- a/packages/PrintSpooler/Android.mk
+++ b/packages/PrintSpooler/Android.mk
@@ -24,4 +24,6 @@
LOCAL_JAVA_LIBRARIES := framework-base
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+
include $(BUILD_PACKAGE)
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index e1d0aec..4c0bbb8 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -42,23 +42,23 @@
<uses-permission android:name="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"/>
<application
- android:allowClearUserData="true"
- android:label="@string/app_label"
- android:allowBackup= "false"
- android:supportsRtl="true"
- android:icon="@*android:drawable/ic_print">
+ android:allowClearUserData="true"
+ android:label="@string/app_label"
+ android:allowBackup= "false"
+ android:supportsRtl="true"
+ android:icon="@*android:drawable/ic_print">
<service
- android:name=".PrintSpoolerService"
+ android:name=".model.PrintSpoolerService"
android:exported="true"
android:permission="android.permission.BIND_PRINT_SPOOLER_SERVICE">
</service>
<activity
- android:name=".PrintJobConfigActivity"
+ android:name=".ui.PrintActivity"
android:configChanges="orientation|screenSize"
android:permission="android.permission.BIND_PRINT_SPOOLER_SERVICE"
- android:theme="@style/PrintJobConfigActivityTheme">
+ android:theme="@android:style/Theme.DeviceDefault.NoActionBar">
<intent-filter>
<action android:name="android.print.PRINT_DIALOG" />
<category android:name="android.intent.category.DEFAULT" />
@@ -67,7 +67,7 @@
</activity>
<activity
- android:name=".SelectPrinterActivity"
+ android:name=".ui.SelectPrinterActivity"
android:label="@string/all_printers_label"
android:theme="@style/SelectPrinterActivityTheme"
android:exported="false">
diff --git a/packages/PrintSpooler/res/drawable-hdpi/ic_expand_less_24dp.png b/packages/PrintSpooler/res/drawable-hdpi/ic_expand_less_24dp.png
new file mode 100644
index 0000000..d2e5408
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-hdpi/ic_expand_less_24dp.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-hdpi/ic_expand_more_24dp.png b/packages/PrintSpooler/res/drawable-hdpi/ic_expand_more_24dp.png
new file mode 100644
index 0000000..f4c4b0c
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-hdpi/ic_expand_more_24dp.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-hdpi/ic_grayedout_printer.png b/packages/PrintSpooler/res/drawable-hdpi/ic_grayedout_printer.png
new file mode 100644
index 0000000..5e54970
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-hdpi/ic_grayedout_printer.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-hdpi/print_button_background.png b/packages/PrintSpooler/res/drawable-hdpi/print_button_background.png
new file mode 100644
index 0000000..88e8495
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-hdpi/print_button_background.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-mdpi/ic_expand_less_24dp.png b/packages/PrintSpooler/res/drawable-mdpi/ic_expand_less_24dp.png
new file mode 100644
index 0000000..3220eea
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-mdpi/ic_expand_less_24dp.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-mdpi/ic_expand_more_24dp.png b/packages/PrintSpooler/res/drawable-mdpi/ic_expand_more_24dp.png
new file mode 100644
index 0000000..5530f52
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-mdpi/ic_expand_more_24dp.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-mdpi/ic_grayedout_printer.png b/packages/PrintSpooler/res/drawable-mdpi/ic_grayedout_printer.png
new file mode 100644
index 0000000..5e54970
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-mdpi/ic_grayedout_printer.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-mdpi/print_button_background.png b/packages/PrintSpooler/res/drawable-mdpi/print_button_background.png
new file mode 100644
index 0000000..3a37b27
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-mdpi/print_button_background.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xhdpi/ic_expand_less_24dp.png b/packages/PrintSpooler/res/drawable-xhdpi/ic_expand_less_24dp.png
new file mode 100644
index 0000000..f0074275
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-xhdpi/ic_expand_less_24dp.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xhdpi/ic_expand_more_24dp.png b/packages/PrintSpooler/res/drawable-xhdpi/ic_expand_more_24dp.png
new file mode 100644
index 0000000..43debb3
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-xhdpi/ic_expand_more_24dp.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xhdpi/ic_grayedout_printer.png b/packages/PrintSpooler/res/drawable-xhdpi/ic_grayedout_printer.png
new file mode 100644
index 0000000..5e54970
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-xhdpi/ic_grayedout_printer.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xhdpi/print_button_background.png b/packages/PrintSpooler/res/drawable-xhdpi/print_button_background.png
new file mode 100644
index 0000000..b2ed8cd
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-xhdpi/print_button_background.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xxhdpi/ic_expand_less_24dp.png b/packages/PrintSpooler/res/drawable-xxhdpi/ic_expand_less_24dp.png
new file mode 100644
index 0000000..39bc2ba
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-xxhdpi/ic_expand_less_24dp.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xxhdpi/ic_expand_more_24dp.png b/packages/PrintSpooler/res/drawable-xxhdpi/ic_expand_more_24dp.png
new file mode 100644
index 0000000..664f3f2
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-xxhdpi/ic_expand_more_24dp.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xxxhdpi/ic_expand_less_24dp.png b/packages/PrintSpooler/res/drawable-xxxhdpi/ic_expand_less_24dp.png
new file mode 100644
index 0000000..fe9c539
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-xxxhdpi/ic_expand_less_24dp.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable-xxxhdpi/ic_expand_more_24dp.png b/packages/PrintSpooler/res/drawable-xxxhdpi/ic_expand_more_24dp.png
new file mode 100644
index 0000000..18d075c
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable-xxxhdpi/ic_expand_more_24dp.png
Binary files differ
diff --git a/packages/PrintSpooler/res/drawable/ic_expand_less.xml b/packages/PrintSpooler/res/drawable/ic_expand_less.xml
new file mode 100644
index 0000000..b0c7d51
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable/ic_expand_less.xml
@@ -0,0 +1,43 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true">
+
+ <item
+ android:state_checked="true">
+ <bitmap
+ android:src="@drawable/ic_expand_less_24dp"
+ android:tint="?android:attr/colorControlActivated">
+ </bitmap>
+ </item>
+
+ <item
+ android:state_pressed="true">
+ <bitmap
+ android:src="@drawable/ic_expand_less_24dp"
+ android:tint="?android:attr/colorControlActivated">
+ </bitmap>
+ </item>
+
+ <item>
+ <bitmap
+ android:src="@drawable/ic_expand_less_24dp"
+ android:tint="?android:attr/colorControlNormal">
+ </bitmap>
+ </item>
+
+</selector>
diff --git a/packages/PrintSpooler/res/drawable/ic_expand_more.xml b/packages/PrintSpooler/res/drawable/ic_expand_more.xml
new file mode 100644
index 0000000..b809c25
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable/ic_expand_more.xml
@@ -0,0 +1,43 @@
+<?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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true">
+
+ <item
+ android:state_checked="true">
+ <bitmap
+ android:src="@drawable/ic_expand_more_24dp"
+ android:tint="?android:attr/colorControlActivated">
+ </bitmap>
+ </item>
+
+ <item
+ android:state_pressed="true">
+ <bitmap
+ android:src="@drawable/ic_expand_more_24dp"
+ android:tint="?android:attr/colorControlActivated">
+ </bitmap>
+ </item>
+
+ <item>
+ <bitmap
+ android:src="@drawable/ic_expand_more_24dp"
+ android:tint="?android:attr/colorControlNormal">
+ </bitmap>
+ </item>
+
+</selector>
diff --git a/core/res/res/drawable/item_background_quantum.xml b/packages/PrintSpooler/res/drawable/print_button.xml
similarity index 78%
copy from core/res/res/drawable/item_background_quantum.xml
copy to packages/PrintSpooler/res/drawable/print_button.xml
index 039ca51..b59afba 100644
--- a/core/res/res/drawable/item_background_quantum.xml
+++ b/packages/PrintSpooler/res/drawable/print_button.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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.
@@ -15,8 +16,8 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:tint="?attr/colorControlHighlight">
- <item android:id="@id/mask">
- <color android:color="@color/white" />
+ android:color="@color/print_button_tint_color">
+ <item
+ android:drawable="@drawable/print_button_background">
</item>
-</ripple>
\ No newline at end of file
+</ripple>
diff --git a/packages/PrintSpooler/res/layout/print_activity.xml b/packages/PrintSpooler/res/layout/print_activity.xml
new file mode 100644
index 0000000..9715322
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/print_activity.xml
@@ -0,0 +1,389 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<com.android.printspooler.widget.ContentView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:printspooler="http://schemas.android.com/apk/res/com.android.printspooler"
+ android:id="@+id/options_content"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:visibility="invisible"
+ android:background="?android:attr/colorForeground">
+
+ <FrameLayout
+ android:id="@+id/static_content"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="16dip"
+ android:background="?android:attr/colorForegroundInverse">
+
+ <!-- Destination -->
+
+ <Spinner
+ android:id="@+id/destination_spinner"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:dropDownWidth="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall">
+ </Spinner>
+
+ </FrameLayout>
+
+ <!-- Summary -->
+
+ <LinearLayout
+ android:id="@+id/summary_content"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:orientation="horizontal"
+ android:background="?android:attr/colorForegroundInverse">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:layout_marginStart="12dip"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:labelFor="@+id/copies_count_summary"
+ android:text="@string/label_copies_summary">
+ </TextView>
+
+ <TextView
+ android:id="@+id/copies_count_summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:layout_marginStart="16dip"
+ android:textAppearance="?android:attr/textAppearanceMedium">
+ </TextView>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:layout_marginStart="32dip"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:labelFor="@+id/paper_size_summary"
+ android:text="@string/label_paper_size_summary">
+ </TextView>
+
+ <TextView
+ android:id="@+id/paper_size_summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:layout_marginStart="16dip"
+ android:textAppearance="?android:attr/textAppearanceMedium">
+ </TextView>
+
+ </LinearLayout>
+
+ <FrameLayout
+ android:id="@+id/dynamic_content"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dip">
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/draggable_content"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <com.android.printspooler.widget.PrintOptionsLayout
+ android:id="@+id/options_container"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorForegroundInverse"
+ printspooler:columnCount="@integer/print_option_column_count">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip"
+ android:orientation="vertical">
+
+ <!-- Copies -->
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:layout_marginStart="12dip"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:labelFor="@+id/copies_edittext"
+ android:text="@string/label_copies">
+ </TextView>
+
+ <view
+ class="com.android.printspooler.widget.FirstFocusableEditText"
+ android:id="@+id/copies_edittext"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ style="?android:attr/editTextStyle"
+ android:inputType="numberDecimal">
+ </view>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip"
+ android:orientation="vertical">
+
+ <!-- Paper size -->
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:layout_marginStart="12dip"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:labelFor="@+id/paper_size_spinner"
+ android:text="@string/label_paper_size">
+ </TextView>
+
+ <Spinner
+ android:id="@+id/paper_size_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ style="@style/PrintOptionSpinnerStyle">
+ </Spinner>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip"
+ android:orientation="vertical">
+
+ <!-- Color -->
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:layout_marginStart="12dip"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:labelFor="@+id/color_spinner"
+ android:text="@string/label_color">
+ </TextView>
+
+ <Spinner
+ android:id="@+id/color_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ style="@style/PrintOptionSpinnerStyle">
+ </Spinner>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip"
+ android:orientation="vertical">
+
+ <!-- Orientation -->
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:layout_marginStart="12dip"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:labelFor="@+id/orientation_spinner"
+ android:text="@string/label_orientation">
+ </TextView>
+
+ <Spinner
+ android:id="@+id/orientation_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ style="@style/PrintOptionSpinnerStyle">
+ </Spinner>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip"
+ android:orientation="vertical">
+
+ <!-- Range options -->
+
+ <TextView
+ android:id="@+id/range_options_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:layout_marginStart="12dip"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:labelFor="@+id/range_options_spinner"
+ android:text="@string/page_count_unknown">
+ </TextView>
+
+ <Spinner
+ android:id="@+id/range_options_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ style="@style/PrintOptionSpinnerStyle">
+ </Spinner>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip"
+ android:orientation="vertical">
+
+ <!-- Pages -->
+
+ <TextView
+ android:id="@+id/page_range_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dip"
+ android:layout_marginStart="12dip"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:text="@string/pages_range_example"
+ android:labelFor="@+id/page_range_edittext"
+ android:textAllCaps="false"
+ android:visibility="visible">
+ </TextView>
+
+ <view
+ class="com.android.printspooler.widget.FirstFocusableEditText"
+ android:id="@+id/page_range_edittext"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|fill_horizontal"
+ style="@style/PrintOptionEditTextStyle"
+ android:visibility="visible"
+ android:inputType="textNoSuggestions">
+ </view>
+
+ </LinearLayout>
+
+ </com.android.printspooler.widget.PrintOptionsLayout>
+
+ <!-- More options -->
+
+ <LinearLayout
+ android:id="@+id/more_options_container"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="28dip"
+ android:paddingEnd="28dip"
+ android:orientation="vertical"
+ android:visibility="visible"
+ android:background="?android:attr/colorForegroundInverse">
+
+ <ImageView
+ android:layout_width="fill_parent"
+ android:layout_height="1dip"
+ android:layout_gravity="fill_horizontal"
+ android:background="?android:attr/colorControlNormal"
+ android:contentDescription="@null">
+ </ImageView>
+
+ <Button
+ android:id="@+id/more_options_button"
+ style="?android:attr/borderlessButtonStyle"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_horizontal"
+ android:text="@string/more_options_button"
+ android:gravity="start|center_vertical"
+ android:textAllCaps="false">
+ </Button>
+
+ <ImageView
+ android:layout_width="fill_parent"
+ android:layout_height="1dip"
+ android:layout_gravity="fill_horizontal"
+ android:background="?android:attr/colorControlNormal"
+ android:contentDescription="@null">
+ </ImageView>
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <!-- Expand/collapse handle -->
+
+ <FrameLayout
+ android:id="@+id/expand_collapse_handle"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeightSmall"
+ android:layout_marginBottom="28dip"
+ android:background="?android:attr/colorForegroundInverse"
+ android:elevation="12dip">
+
+ <ImageButton
+ android:id="@+id/expand_collapse_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:background="@drawable/ic_expand_more">
+ </ImageButton>
+
+ </FrameLayout>
+
+ </LinearLayout>
+
+ <!-- Print button -->
+
+ <ImageButton
+ android:id="@+id/print_button"
+ style="?android:attr/buttonStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_marginEnd="16dip"
+ android:elevation="12dip"
+ android:background="@drawable/print_button"
+ android:src="@*android:drawable/ic_print">
+ </ImageButton>
+
+ </FrameLayout>
+
+
+ <FrameLayout
+ android:id="@+id/embedded_content_container"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:animateLayoutChanges="true">
+ </FrameLayout>
+
+</com.android.printspooler.widget.ContentView>
diff --git a/packages/PrintSpooler/res/layout/print_error_fragment.xml b/packages/PrintSpooler/res/layout/print_error_fragment.xml
new file mode 100644
index 0000000..dc44339
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/print_error_fragment.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="12dip"
+ android:src="@drawable/ic_grayedout_printer"
+ android:contentDescription="@null">
+ </ImageView>
+
+ <TextView
+ android:id="@+id/message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/print_error_default_message"
+ android:textAppearance="?android:attr/textAppearanceLargeInverse">
+ </TextView>
+
+ <Button
+ android:id="@+id/action_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/print_error_retry">
+ </Button>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml
deleted file mode 100644
index 3303ef1..0000000
--- a/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<com.android.printspooler.PrintDialogFrame xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <FrameLayout
- android:id="@+id/content_container"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@color/container_background">
- </FrameLayout>
-</com.android.printspooler.PrintDialogFrame>
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
deleted file mode 100644
index e50a7af..0000000
--- a/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
+++ /dev/null
@@ -1,282 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:scrollbars="vertical">
-
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <!-- Destination -->
-
- <Spinner
- android:id="@+id/destination_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_horizontal"
- android:layout_marginTop="24dip"
- android:layout_marginStart="24dip"
- android:layout_marginEnd="24dip"
- android:minHeight="?android:attr/listPreferredItemHeightSmall">
- </Spinner>
-
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="24dip"
- android:orientation="horizontal"
- android:baselineAligned="false">
-
- <LinearLayout
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:orientation="vertical">
-
- <!-- Copies -->
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginStart="36dip"
- android:layout_marginEnd="6dip"
- android:textAppearance="@style/PrintOptionTitleTextAppearance"
- android:labelFor="@+id/copies_edittext"
- android:text="@string/label_copies">
- </TextView>
-
- <view
- class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
- android:id="@+id/copies_edittext"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="24dip"
- android:layout_marginEnd="6dip"
- style="@style/PrintOptionEditTextStyle"
- android:inputType="numberDecimal">
- </view>
-
- <!-- Color -->
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginStart="36dip"
- android:layout_marginEnd="6dip"
- android:textAppearance="@style/PrintOptionTitleTextAppearance"
- android:labelFor="@+id/color_spinner"
- android:text="@string/label_color">
- </TextView>
-
- <Spinner
- android:id="@+id/color_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="24dip"
- android:layout_marginEnd="6dip"
- style="@style/PrintOptionSpinnerStyle">
- </Spinner>
-
- <!-- Range options -->
-
- <TextView
- android:id="@+id/range_options_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginStart="36dip"
- android:textAppearance="@style/PrintOptionTitleTextAppearance"
- android:labelFor="@+id/range_options_spinner"
- android:text="@string/page_count_unknown">
- </TextView>
-
- <Spinner
- android:id="@+id/range_options_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="24dip"
- android:layout_marginEnd="6dip"
- style="@style/PrintOptionSpinnerStyle">
- </Spinner>
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:orientation="vertical">
-
- <!-- Paper size -->
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginStart="18dip"
- android:layout_marginEnd="24dip"
- android:textAppearance="@style/PrintOptionTitleTextAppearance"
- android:labelFor="@+id/paper_size_spinner"
- android:text="@string/label_paper_size">
- </TextView>
-
- <Spinner
- android:id="@+id/paper_size_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="6dip"
- android:layout_marginEnd="24dip"
- style="@style/PrintOptionSpinnerStyle">
- </Spinner>
-
- <!-- Orientation -->
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginStart="18dip"
- android:layout_marginEnd="24dip"
- android:textAppearance="@style/PrintOptionTitleTextAppearance"
- android:labelFor="@+id/orientation_spinner"
- android:text="@string/label_orientation">
- </TextView>
-
- <Spinner
- android:id="@+id/orientation_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="6dip"
- android:layout_marginEnd="24dip"
- style="@style/PrintOptionSpinnerStyle">
- </Spinner>
-
- <!-- Pages -->
-
- <TextView
- android:id="@+id/page_range_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginStart="12dip"
- android:layout_marginEnd="24dip"
- android:textAppearance="@style/PrintOptionTitleTextAppearance"
- android:text="@string/pages_range_example"
- android:labelFor="@+id/page_range_edittext"
- android:textAllCaps="false">
- </TextView>
-
- <view
- class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
- android:id="@+id/page_range_edittext"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="6dip"
- android:layout_marginEnd="24dip"
- android:layout_gravity="bottom|fill_horizontal"
- style="@style/PrintOptionEditTextStyle"
- android:visibility="gone"
- android:inputType="textNoSuggestions">
- </view>
-
- </LinearLayout>
-
- </LinearLayout>
-
- <!-- Advanced settings button -->
-
- <LinearLayout
- android:id="@+id/advanced_settings_container"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:visibility="gone">
-
- <ImageView
- android:layout_width="fill_parent"
- android:layout_height="1dip"
- android:layout_marginStart="24dip"
- android:layout_marginEnd="24dip"
- android:layout_gravity="fill_horizontal"
- android:background="@color/separator"
- android:contentDescription="@null">
- </ImageView>
-
- <Button
- android:id="@+id/advanced_settings_button"
- style="?android:attr/buttonBarButtonStyle"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="24dip"
- android:layout_marginEnd="24dip"
- android:layout_gravity="fill_horizontal"
- android:text="@string/advanced_settings_button"
- android:gravity="start|center_vertical"
- android:textSize="16sp"
- android:textColor="@color/item_text_color">
- </Button>
-
- <ImageView
- android:layout_width="fill_parent"
- android:layout_height="1dip"
- android:layout_gravity="fill_horizontal"
- android:layout_marginStart="24dip"
- android:layout_marginEnd="24dip"
- android:background="@color/separator"
- android:contentDescription="@null">
- </ImageView>
-
- </LinearLayout>
-
- <!-- Print button -->
-
- <FrameLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="24dip"
- android:background="@color/action_button_background">
-
- <ImageView
- android:layout_width="fill_parent"
- android:layout_height="1dip"
- android:layout_gravity="fill_horizontal"
- android:background="@color/separator"
- android:contentDescription="@null">
- </ImageView>
-
- <Button
- android:id="@+id/print_button"
- style="?android:attr/buttonBarButtonStyle"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_horizontal"
- android:text="@string/print_button"
- android:textSize="16sp"
- android:textColor="@color/item_text_color">
- </Button>
-
- </FrameLayout>
-
- </LinearLayout>
-
-</ScrollView>
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml
deleted file mode 100644
index d9f0a9a..0000000
--- a/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/content_generating"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/message"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="16dip"
- android:layout_marginEnd="16dip"
- android:layout_marginTop="32dip"
- android:layout_marginBottom="32dip"
- android:layout_gravity="center"
- style="?android:attr/buttonBarButtonStyle"
- android:ellipsize="end"
- android:text="@string/print_error_default_message"
- android:textColor="@color/important_text"
- android:textSize="16sp">
- </TextView>
-
- </LinearLayout>
-
- <FrameLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@color/action_button_background">
-
- <View
- android:layout_width="fill_parent"
- android:layout_height="1dip"
- android:background="@color/separator">
- </View>
-
- <Button
- android:id="@+id/ok_button"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_horizontal"
- style="?android:attr/buttonBarButtonStyle"
- android:text="@android:string/ok"
- android:textSize="16sp"
- android:textColor="@color/important_text">
- </Button>
-
- </FrameLayout>
-
-</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_content_generating.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_content_generating.xml
deleted file mode 100644
index 10602ee..0000000
--- a/packages/PrintSpooler/res/layout/print_job_config_activity_content_generating.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/content_generating"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="16dip"
- android:layout_marginEnd="16dip"
- android:layout_gravity="center"
- style="?android:attr/buttonBarButtonStyle"
- android:singleLine="true"
- android:ellipsize="end"
- android:text="@string/generating_print_job"
- android:textColor="@color/important_text"
- android:textSize="16sp">
- </TextView>
-
- <ProgressBar
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="32dip"
- android:layout_marginEnd="32dip"
- android:layout_marginTop="16dip"
- android:layout_marginBottom="32dip"
- android:layout_gravity="center_horizontal"
- style="?android:attr/progressBarStyleLarge">
- </ProgressBar>
-
- </LinearLayout>
-
- <FrameLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@color/action_button_background">
-
- <View
- android:layout_width="fill_parent"
- android:layout_height="1dip"
- android:background="@color/separator">
- </View>
-
- <Button
- android:id="@+id/cancel_button"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="fill_horizontal"
- style="?android:attr/buttonBarButtonStyle"
- android:text="@string/cancel"
- android:textSize="16sp"
- android:textColor="@color/important_text">
- </Button>
-
- </FrameLayout>
-
-</LinearLayout>
diff --git a/packages/PrintSpooler/res/layout/print_progress_fragment.xml b/packages/PrintSpooler/res/layout/print_progress_fragment.xml
new file mode 100644
index 0000000..212da9e
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/print_progress_fragment.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="12dip"
+ android:src="@drawable/ic_grayedout_printer"
+ android:contentDescription="@null">
+ </ImageView>
+
+ <ProgressBar
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:indeterminate="true"
+ style="?android:attr/progressBarStyleHorizontal">
+ </ProgressBar>
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center"
+ android:animateLayoutChanges="true">
+
+ <TextView
+ android:id="@+id/message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ android:text="@string/print_operation_canceling"
+ android:visibility="gone">
+ </TextView>
+
+ <Button
+ android:id="@+id/cancel_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@android:string/cancel">
+ </Button>
+
+ </FrameLayout>
+
+</LinearLayout>
+
diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
index 1a61b99..43d8aaf 100644
--- a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
@@ -19,7 +19,7 @@
android:layout_height="wrap_content"
android:paddingStart="16dip"
android:paddingEnd="16dip"
- android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:minHeight="56dip"
android:orientation="horizontal"
android:gravity="start|center_vertical">
@@ -49,7 +49,7 @@
android:ellipsize="end"
android:textIsSelectable="false"
android:gravity="top|start"
- android:textColor="@color/item_text_color"
+ android:textColor="?android:attr/textColorPrimary"
android:duplicateParentState="true">
</TextView>
@@ -62,7 +62,7 @@
android:ellipsize="end"
android:textIsSelectable="false"
android:visibility="gone"
- android:textColor="@color/print_option_title"
+ android:textColor="?android:attr/textColorPrimary"
android:duplicateParentState="true">
</TextView>
diff --git a/packages/PrintSpooler/res/layout/printer_list_item.xml b/packages/PrintSpooler/res/layout/printer_list_item.xml
index 47eb0b5..1f5efbc 100644
--- a/packages/PrintSpooler/res/layout/printer_list_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_list_item.xml
@@ -15,13 +15,13 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:orientation="horizontal"
- android:gravity="start|center_vertical">
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:orientation="horizontal"
+ android:gravity="start|center_vertical">
<ImageView
android:id="@+id/icon"
@@ -31,7 +31,7 @@
android:layout_marginEnd="8dip"
android:duplicateParentState="true"
android:contentDescription="@null"
- android:visibility="gone">
+ android:visibility="invisible">
</ImageView>
<LinearLayout
@@ -49,7 +49,7 @@
android:ellipsize="end"
android:textIsSelectable="false"
android:gravity="top|start"
- android:textColor="@color/item_text_color"
+ android:textColor="?android:attr/textColorSecondary"
android:duplicateParentState="true">
</TextView>
@@ -62,7 +62,7 @@
android:ellipsize="end"
android:textIsSelectable="false"
android:visibility="gone"
- android:textColor="@color/print_option_title"
+ android:textColor="?android:attr/textColorSecondary"
android:duplicateParentState="true">
</TextView>
diff --git a/packages/PrintSpooler/res/layout/select_printer_activity.xml b/packages/PrintSpooler/res/layout/select_printer_activity.xml
index 4488b6a..173057b 100644
--- a/packages/PrintSpooler/res/layout/select_printer_activity.xml
+++ b/packages/PrintSpooler/res/layout/select_printer_activity.xml
@@ -19,12 +19,16 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent">
- <fragment
- android:name="com.android.printspooler.SelectPrinterFragment"
- android:id="@+id/select_printer_fragment"
+ <ListView
+ android:id="@android:id/list"
android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- </fragment>
+ android:layout_height="fill_parent"
+ android:paddingStart="@dimen/printer_list_view_padding_start"
+ android:paddingEnd="@dimen/printer_list_view_padding_end"
+ android:scrollbarStyle="outsideOverlay"
+ android:cacheColorHint="@android:color/transparent"
+ android:scrollbarAlwaysDrawVerticalTrack="true" >
+ </ListView>
<FrameLayout
android:id="@+id/empty_print_state"
diff --git a/packages/PrintSpooler/res/layout/select_printer_fragment.xml b/packages/PrintSpooler/res/layout/select_printer_fragment.xml
deleted file mode 100644
index bbd012e..0000000
--- a/packages/PrintSpooler/res/layout/select_printer_fragment.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<ListView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/list"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:paddingStart="@dimen/printer_list_view_padding_start"
- android:paddingEnd="@dimen/printer_list_view_padding_end"
- android:scrollbarStyle="outsideOverlay"
- android:cacheColorHint="@android:color/transparent"
- android:scrollbarAlwaysDrawVerticalTrack="true" >
-</ListView>
diff --git a/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml
index c3c5021..1fb221a 100644
--- a/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml
+++ b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml
@@ -32,7 +32,7 @@
android:ellipsize="end"
android:textIsSelectable="false"
android:gravity="top|left"
- android:textColor="@color/item_text_color"
+ android:textColor="?android:attr/textColorPrimary"
android:duplicateParentState="true">
</TextView>
@@ -45,7 +45,7 @@
android:ellipsize="end"
android:textIsSelectable="false"
android:visibility="gone"
- android:textColor="@color/print_option_title"
+ android:textColor="?android:attr/textColorPrimary"
android:duplicateParentState="true">
</TextView>
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index a10a5a0..2810785 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Drukwaglys"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Drukkerinstellings"</string>
- <string name="print_button" msgid="645164566271246268">"Druk"</string>
- <string name="save_button" msgid="1921310454071758999">"Stoor"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Meer opsies"</string>
<string name="label_destination" msgid="9132510997381599275">"Bestemming"</string>
<string name="label_copies" msgid="3634531042822968308">"Afskrifte"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Papiergrootte"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Afskrifte:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Papiergrootte"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Papiergrootte:"</string>
<string name="label_color" msgid="1108690305218188969">"Kleur"</string>
<string name="label_orientation" msgid="2853142581990496477">"Oriëntasie"</string>
<string name="label_pages" msgid="6300874667546617333">"Bladsye (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Geen verbinding met drukker nie"</string>
<string name="reason_unknown" msgid="5507940196503246139">"onbekend"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nie beskikbaar nie"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Kon nie uitdruktaak genereer nie"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Swart en wit"</item>
<item msgid="2762241247228983754">"Kleur"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Alles"</item>
<item msgid="6812869625222503603">"Reikwydte"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Kon nie na lêer skryf nie"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Kon nie uitdruktaak genereer nie"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Herprobeer"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Drukker nie beskikbaar nie"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Kanselleer tans …"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index be64c95..dfcc4a1 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"የህትመት አስተላላፊ"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"የአታሚ ቅንብሮች"</string>
- <string name="print_button" msgid="645164566271246268">"አትም"</string>
- <string name="save_button" msgid="1921310454071758999">"አስቀምጥ"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"ተጨማሪ አማራጮች"</string>
<string name="label_destination" msgid="9132510997381599275">"መድረሻ"</string>
<string name="label_copies" msgid="3634531042822968308">"ቅጂዎች"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"የወረቀት መጠን"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"ቅጂዎች፦"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"የወረቀት መጠን"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"የወረቀት መጠን፦"</string>
<string name="label_color" msgid="1108690305218188969">"ቀለም"</string>
<string name="label_orientation" msgid="2853142581990496477">"አቀማመጠ ገፅ"</string>
<string name="label_pages" msgid="6300874667546617333">"ገጾች (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"ከአታሚ ጋር ምንም ግንኙነት የለም"</string>
<string name="reason_unknown" msgid="5507940196503246139">"አይታወቅም"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – አይገኝም"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"የህትመት ስራን ማመንጨት አልተቻለም"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"ጥቁር እና ነጭ"</item>
<item msgid="2762241247228983754">"ቀለም"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"ሁሉም"</item>
<item msgid="6812869625222503603">"ምጥጥነ ገጽታ"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"ወደ ፋይል መጻፍ አልተቻለም"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"የህትመት ስራን ማመንጨት አልተቻለም"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"እንደገና ይሞክሩ"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"አታሚ አይገኝም"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"በመሰረዝ ላይ…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index b883f93..ca6100b 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"إعدادات الطابعة"</string>
- <string name="print_button" msgid="645164566271246268">"طباعة"</string>
- <string name="save_button" msgid="1921310454071758999">"حفظ"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"خيارات أخرى"</string>
<string name="label_destination" msgid="9132510997381599275">"الوجهة"</string>
<string name="label_copies" msgid="3634531042822968308">"عدد النسخ"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"حجم الورق"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"النُسخ:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"حجم الورق"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"حجم الورق:"</string>
<string name="label_color" msgid="1108690305218188969">"ألوان"</string>
<string name="label_orientation" msgid="2853142581990496477">"الاتجاه"</string>
<string name="label_pages" msgid="6300874667546617333">"الصفحات (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"لا يوجد اتصال بالطابعة"</string>
<string name="reason_unknown" msgid="5507940196503246139">"غير معروف"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – غير متاحة"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"تعذر إنشاء عملية الطباعة"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"أبيض وأسود"</item>
<item msgid="2762241247228983754">"ملونة"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"الكل"</item>
<item msgid="6812869625222503603">"النطاق"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"تعذرت الكتابة إلى الملف"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"تعذر إنشاء عملية الطباعة"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"إعادة المحاولة"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"الطابعة غير متاحة"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"جارٍ الإلغاء…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index 4009aa2..6c52d16 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Спулер за печат"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Настройки на принтера"</string>
- <string name="print_button" msgid="645164566271246268">"Печат"</string>
- <string name="save_button" msgid="1921310454071758999">"Запазване"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Още опции"</string>
<string name="label_destination" msgid="9132510997381599275">"Местоназначение"</string>
<string name="label_copies" msgid="3634531042822968308">"Копия"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Размер на хартията"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Копия:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Размер на хартията"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Размер на хартията:"</string>
<string name="label_color" msgid="1108690305218188969">"Цвят"</string>
<string name="label_orientation" msgid="2853142581990496477">"Ориентация"</string>
<string name="label_pages" msgid="6300874667546617333">"Страници (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Няма връзка с принтера"</string>
<string name="reason_unknown" msgid="5507940196503246139">"няма данни"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – не е налице"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Заданието за отпечатване не можа да се генерира"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Черно-бяло"</item>
<item msgid="2762241247228983754">"Цветно"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Всички"</item>
<item msgid="6812869625222503603">"Поредица"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Не можа да се запише във файла"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Заданието за отпечатване не можа да се генерира"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Нов опит"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Няма достъп до принтера"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Анулира се…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index a429dd5..53190ab 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Gest. cues impr."</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Configuració impressora"</string>
- <string name="print_button" msgid="645164566271246268">"Imprimeix"</string>
- <string name="save_button" msgid="1921310454071758999">"Desa"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Més opcions"</string>
<string name="label_destination" msgid="9132510997381599275">"Destinació"</string>
<string name="label_copies" msgid="3634531042822968308">"Còpies"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Mida del paper"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Còpies:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Mida del paper"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Mida del paper:"</string>
<string name="label_color" msgid="1108690305218188969">"Color"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientació"</string>
<string name="label_pages" msgid="6300874667546617333">"Pàgines (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"No hi ha connexió amb la impressora"</string>
<string name="reason_unknown" msgid="5507940196503246139">"desconegut"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>: no disponible"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"No s\'ha pogut generar la tasca d\'impressió"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Blanc i negre"</item>
<item msgid="2762241247228983754">"Color"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Tots"</item>
<item msgid="6812869625222503603">"Interval"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"No s\'ha pogut escriure al fitxer."</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"No s\'ha pogut generar la tasca d\'impressió"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Torna-ho a provar"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Impressora no disponible"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"S\'està cancel·lant…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index 3ddc701..68e8ec3 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Nastavení tiskárny"</string>
- <string name="print_button" msgid="645164566271246268">"Tisk"</string>
- <string name="save_button" msgid="1921310454071758999">"Uložit"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Další možnosti"</string>
<string name="label_destination" msgid="9132510997381599275">"Cíl"</string>
<string name="label_copies" msgid="3634531042822968308">"Kopie"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Velikost papíru"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Počet kopií:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Velikost papíru"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Velikost papíru:"</string>
<string name="label_color" msgid="1108690305218188969">"Barva"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientace"</string>
<string name="label_pages" msgid="6300874667546617333">"STRÁNKY (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nelze se připojit k tiskárně"</string>
<string name="reason_unknown" msgid="5507940196503246139">"neznámé"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – není k dispozici"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Tiskovou úlohu nelze vytvořit"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Černobíle"</item>
<item msgid="2762241247228983754">"Barevně"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Vše"</item>
<item msgid="6812869625222503603">"Rozsah"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Do souboru nelze zapisovat."</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Tiskovou úlohu nelze vytvořit"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Opakovat"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Tiskárna je nedostupná."</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Rušení…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index 1a871f8..368c3768 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Printerindstillinger"</string>
- <string name="print_button" msgid="645164566271246268">"Udskriv"</string>
- <string name="save_button" msgid="1921310454071758999">"Gem"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Flere valgmuligheder"</string>
<string name="label_destination" msgid="9132510997381599275">"Destination"</string>
<string name="label_copies" msgid="3634531042822968308">"Kopier"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Papirstørrelse"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Kopier:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Papirstørrelse"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Papirstørrelse:"</string>
<string name="label_color" msgid="1108690305218188969">"Farve"</string>
<string name="label_orientation" msgid="2853142581990496477">"Retning"</string>
<string name="label_pages" msgid="6300874667546617333">"Sider (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen forbindelse til printer"</string>
<string name="reason_unknown" msgid="5507940196503246139">"ukendt"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ikke tilgængelig"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Der kunne ikke genereres et udskriftsjob"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Sort/hvid"</item>
<item msgid="2762241247228983754">"Farve"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Alle"</item>
<item msgid="6812869625222503603">"Interval"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Der kunne ikke skrives til filen"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Der kunne ikke genereres et udskriftsjob"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Prøv igen"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Printeren er utilgængelig"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Annullerer…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index 6b83ac3..8dc52a2 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Druck-Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Druckereinstellungen"</string>
- <string name="print_button" msgid="645164566271246268">"Drucken"</string>
- <string name="save_button" msgid="1921310454071758999">"Speichern"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Weitere Optionen"</string>
<string name="label_destination" msgid="9132510997381599275">"Ziel"</string>
<string name="label_copies" msgid="3634531042822968308">"Exemplare"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Papiergröße"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Kopien:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Papierformat"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Papierformat:"</string>
<string name="label_color" msgid="1108690305218188969">"Farbe"</string>
<string name="label_orientation" msgid="2853142581990496477">"Ausrichtung"</string>
<string name="label_pages" msgid="6300874667546617333">"Seiten (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Keine Verbindung zum Drucker"</string>
<string name="reason_unknown" msgid="5507940196503246139">"unbekannt"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nicht verfügbar"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Druckauftrag konnte nicht generiert werden."</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Schwarz-weiß"</item>
<item msgid="2762241247228983754">"Farbe"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Alle"</item>
<item msgid="6812869625222503603">"Bereich"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Fehler beim Schreiben in Datei"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Druckauftrag konnte nicht generiert werden."</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Erneut versuchen"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Drucker nicht verfügbar"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Vorgang wird abgebrochen..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml
index 795e730..542caf9 100644
--- a/packages/PrintSpooler/res/values-el/strings.xml
+++ b/packages/PrintSpooler/res/values-el/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Λογισμικό ουράς εκτύπωσης"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Ρυθμίσεις εκτυπωτή"</string>
- <string name="print_button" msgid="645164566271246268">"Εκτύπωση"</string>
- <string name="save_button" msgid="1921310454071758999">"Αποθήκευση"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Περισσότερες επιλογές"</string>
<string name="label_destination" msgid="9132510997381599275">"Προορισμός"</string>
<string name="label_copies" msgid="3634531042822968308">"Αντίγραφα"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Μέγεθος χαρτιού"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Αντίγραφα:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Μεγέθος χαρτιού"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Μέγεθος χαρτιού:"</string>
<string name="label_color" msgid="1108690305218188969">"Χρώμα"</string>
<string name="label_orientation" msgid="2853142581990496477">"Προσανατολισμός"</string>
<string name="label_pages" msgid="6300874667546617333">"Σελίδες (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Δεν υπάρχει σύνδεση με εκτυπωτή"</string>
<string name="reason_unknown" msgid="5507940196503246139">"άγνωστο"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – μη διαθέσιμο"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Δεν ήταν δυνατή η δημιουργία εργασίας εκτύπωσης"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Ασπρόμαυρο"</item>
<item msgid="2762241247228983754">"Χρώμα"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Όλα"</item>
<item msgid="6812869625222503603">"Εύρος"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Δεν ήταν δυνατή η εγγραφή στο αρχείο"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Δεν ήταν δυνατή η δημιουργία εργασίας εκτύπωσης"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Επανάληψη"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Ο εκτυπωτής δεν είναι διαθέσιμος"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Ακύρωση…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml
index 27372f8..3728437 100644
--- a/packages/PrintSpooler/res/values-en-rGB/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Printer settings"</string>
- <string name="print_button" msgid="645164566271246268">"Print"</string>
- <string name="save_button" msgid="1921310454071758999">"Save"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"More options"</string>
<string name="label_destination" msgid="9132510997381599275">"Destination"</string>
<string name="label_copies" msgid="3634531042822968308">"Copies"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Paper Size"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Copies:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Paper size"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Paper size:"</string>
<string name="label_color" msgid="1108690305218188969">"Colour"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientation"</string>
<string name="label_pages" msgid="6300874667546617333">"Pages (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string>
<string name="reason_unknown" msgid="5507940196503246139">"unknown"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – unavailable"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Couldn\'t generate print job"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Black & White"</item>
<item msgid="2762241247228983754">"Colour"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"All"</item>
<item msgid="6812869625222503603">"Range"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Couldn\'t write to file"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Couldn\'t generate print job"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Retry"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Printer unavailable"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Cancelling…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml
index 27372f8..3728437 100644
--- a/packages/PrintSpooler/res/values-en-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Printer settings"</string>
- <string name="print_button" msgid="645164566271246268">"Print"</string>
- <string name="save_button" msgid="1921310454071758999">"Save"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"More options"</string>
<string name="label_destination" msgid="9132510997381599275">"Destination"</string>
<string name="label_copies" msgid="3634531042822968308">"Copies"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Paper Size"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Copies:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Paper size"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Paper size:"</string>
<string name="label_color" msgid="1108690305218188969">"Colour"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientation"</string>
<string name="label_pages" msgid="6300874667546617333">"Pages (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"No connection to printer"</string>
<string name="reason_unknown" msgid="5507940196503246139">"unknown"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – unavailable"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Couldn\'t generate print job"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Black & White"</item>
<item msgid="2762241247228983754">"Colour"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"All"</item>
<item msgid="6812869625222503603">"Range"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Couldn\'t write to file"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Couldn\'t generate print job"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Retry"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Printer unavailable"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Cancelling…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index c7d12af..90e81bd 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Cola de impresión"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Config. de impresora"</string>
- <string name="print_button" msgid="645164566271246268">"Imprimir"</string>
- <string name="save_button" msgid="1921310454071758999">"Guardar"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Más opciones"</string>
<string name="label_destination" msgid="9132510997381599275">"Destino"</string>
<string name="label_copies" msgid="3634531042822968308">"Copias"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Tamaño del papel"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Copias:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Tamaño del papel"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Tamaño de papel:"</string>
<string name="label_color" msgid="1108690305218188969">"Color"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientación"</string>
<string name="label_pages" msgid="6300874667546617333">"Páginas (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"No hay conexión con la impresora."</string>
<string name="reason_unknown" msgid="5507940196503246139">"desconocido"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>: no disponible"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Error al generar el trabajo de impresión"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Blanco y negro"</item>
<item msgid="2762241247228983754">"Color"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Todas"</item>
<item msgid="6812869625222503603">"Intervalo"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"No se pudo escribir en el archivo."</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Error al generar el trabajo de impresión"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Reintentar"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Impresora no disponible"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Cancelando…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index 0225cad..101831a 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Cola de impresión"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Ajustes de impresora"</string>
- <string name="print_button" msgid="645164566271246268">"Imprimir"</string>
- <string name="save_button" msgid="1921310454071758999">"Guardar"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Más opciones"</string>
<string name="label_destination" msgid="9132510997381599275">"Destino"</string>
<string name="label_copies" msgid="3634531042822968308">"Copias"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Tamaño del papel"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Copias:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Tamaño del papel"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Tamaño del papel:"</string>
<string name="label_color" msgid="1108690305218188969">"Color"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientación"</string>
<string name="label_pages" msgid="6300874667546617333">"Páginas (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"No hay conexión con la impresora"</string>
<string name="reason_unknown" msgid="5507940196503246139">"desconocido"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – no disponible"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Error al generar el trabajo de impresión"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Blanco y negro"</item>
<item msgid="2762241247228983754">"Color"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Todo"</item>
<item msgid="6812869625222503603">"Intervalo"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Error al escribir en el archivo"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Error al generar el trabajo de impresión"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Reintentar"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Impresora no disponible"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Cancelando…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index 2b3b352..24e1e54 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Prindispuuler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Printeri seaded"</string>
- <string name="print_button" msgid="645164566271246268">"Prindi"</string>
- <string name="save_button" msgid="1921310454071758999">"Salvesta"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Rohkem valikuid"</string>
<string name="label_destination" msgid="9132510997381599275">"Sihtkoht"</string>
<string name="label_copies" msgid="3634531042822968308">"Koopiaid"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Paberiformaat"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Koopiad:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Paberi suurus"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Paberi suurus:"</string>
<string name="label_color" msgid="1108690305218188969">"Värv"</string>
<string name="label_orientation" msgid="2853142581990496477">"Suund"</string>
<string name="label_pages" msgid="6300874667546617333">"Lehti (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Printeriühendus puudub"</string>
<string name="reason_unknown" msgid="5507940196503246139">"teadmata"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – pole saadaval"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Prinditööd ei saanud luua"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Mustvalge"</item>
<item msgid="2762241247228983754">"Värv"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Kõik"</item>
<item msgid="6812869625222503603">"Vahemik"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Failile ei saanud kirjutada."</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Prinditööd ei saanud luua"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Proovi uuesti"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Printer pole saadaval"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Tühistamine ..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index 49bae323..9aa0aeb 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"هماهنگکننده چاپ"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"تنظیمات چاپگر"</string>
- <string name="print_button" msgid="645164566271246268">"چاپ"</string>
- <string name="save_button" msgid="1921310454071758999">"ذخیره"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"گزینههای بیشتر"</string>
<string name="label_destination" msgid="9132510997381599275">"مقصد"</string>
<string name="label_copies" msgid="3634531042822968308">"کپیها"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"اندازه کاغذ"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"تعداد نسخهها:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"اندازه کاغذ"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"اندازه کاغذ:"</string>
<string name="label_color" msgid="1108690305218188969">"رنگی"</string>
<string name="label_orientation" msgid="2853142581990496477">"جهت"</string>
<string name="label_pages" msgid="6300874667546617333">"صفحات (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"اتصال با چاپگر برقرار نیست"</string>
<string name="reason_unknown" msgid="5507940196503246139">"نامعلوم"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - در دسترس نیست"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"کار چاپ ایجاد نشد"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"سیاه و سفید"</item>
<item msgid="2762241247228983754">"رنگی"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"همه"</item>
<item msgid="6812869625222503603">"محدوده"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"در فایل نوشته نشد"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"کار چاپ ایجاد نشد"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"امتحان مجدد"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"چاپگر در دسترس نیست"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"در حال لغو…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index 8658e04..a92b860 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Taustatulostus"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Tulostimen asetukset"</string>
- <string name="print_button" msgid="645164566271246268">"Tulosta"</string>
- <string name="save_button" msgid="1921310454071758999">"Tallenna"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Lisäasetukset"</string>
<string name="label_destination" msgid="9132510997381599275">"Kohde"</string>
<string name="label_copies" msgid="3634531042822968308">"Kopiot"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Paperikoko"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Kopiot:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Paperikoko"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Paperikoko:"</string>
<string name="label_color" msgid="1108690305218188969">"Väri"</string>
<string name="label_orientation" msgid="2853142581990496477">"Suunta"</string>
<string name="label_pages" msgid="6300874667546617333">"Sivut (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Ei yhteyttä tulostimeen"</string>
<string name="reason_unknown" msgid="5507940196503246139">"tuntematon"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ei käytettävissä"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Tulostustyötä ei voitu luoda"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Mustavalkoinen"</item>
<item msgid="2762241247228983754">"Väri"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Kaikki"</item>
<item msgid="6812869625222503603">"Väli"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Tiedostoon kirjoittaminen epäonnistui"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Tulostustyötä ei voitu luoda"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Yritä uudelleen"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Tulostin ei ole käytettävissä"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Peruutetaan…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index 9a3352c..b7c0247 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"File d\'att. impr."</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Paramètres de l\'imprimante"</string>
- <string name="print_button" msgid="645164566271246268">"Imprimer"</string>
- <string name="save_button" msgid="1921310454071758999">"Enregistrer"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Plus d\'options"</string>
<string name="label_destination" msgid="9132510997381599275">"Destination"</string>
<string name="label_copies" msgid="3634531042822968308">"Copies"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Format du papier"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Copies :"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Taille du papier"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Taille du papier :"</string>
<string name="label_color" msgid="1108690305218188969">"Couleur"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientation"</string>
<string name="label_pages" msgid="6300874667546617333">"Pages (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Aucune connexion à l\'imprimante"</string>
<string name="reason_unknown" msgid="5507940196503246139">"inconnu"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> — indisponible"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Impossible de générer la tâche d\'impression"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Noir et blanc"</item>
<item msgid="2762241247228983754">"Couleur"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Tous"</item>
<item msgid="6812869625222503603">"Plage"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Impossible d\'écrire dans le fichier"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Impossible de générer la tâche d\'impression"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Réessayer"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Imprimante indisponible"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Annulation en cours..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index 17fabdc..3150269 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Spouler impress."</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Paramètres de l\'imprimante"</string>
- <string name="print_button" msgid="645164566271246268">"Imprimer"</string>
- <string name="save_button" msgid="1921310454071758999">"Enregistrer"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Plus d\'options"</string>
<string name="label_destination" msgid="9132510997381599275">"Destination"</string>
<string name="label_copies" msgid="3634531042822968308">"Copies"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Format du papier"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Copies :"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Taille du papier"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Taille du papier :"</string>
<string name="label_color" msgid="1108690305218188969">"Couleur"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientation"</string>
<string name="label_pages" msgid="6300874667546617333">"Pages (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Aucune connexion à l\'imprimante."</string>
<string name="reason_unknown" msgid="5507940196503246139">"inconnue"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – indisponible"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Impossible de générer la tâche d\'impression."</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Noir et blanc"</item>
<item msgid="2762241247228983754">"Couleur"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Tout"</item>
<item msgid="6812869625222503603">"Plage"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Impossible d\'écrire dans le fichier."</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Impossible de générer la tâche d\'impression."</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Réessayer"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Imprimante indisponible."</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Annulation en cours…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index 60406b7..ad03d7f 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"प्रिंट स्पूलर"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"प्रिंटर सेटिंग"</string>
- <string name="print_button" msgid="645164566271246268">"प्रिंट करें"</string>
- <string name="save_button" msgid="1921310454071758999">"सहेजें"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"अधिक विकल्प"</string>
<string name="label_destination" msgid="9132510997381599275">"गंतव्य"</string>
<string name="label_copies" msgid="3634531042822968308">"प्रतियां"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"कागज़ का आकार"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"प्रतियां:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"काग़ज़ का आकार"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"काग़ज़ का आकार:"</string>
<string name="label_color" msgid="1108690305218188969">"रंग"</string>
<string name="label_orientation" msgid="2853142581990496477">"अभिविन्यास"</string>
<string name="label_pages" msgid="6300874667546617333">"पृष्ठ (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिंटर के लिए कोई कनेक्शन नहीं"</string>
<string name="reason_unknown" msgid="5507940196503246139">"अज्ञात"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – अनुपलब्ध"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"प्रिंट कार्य जनरेट नहीं किया जा सका"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"श्याम और श्वेत"</item>
<item msgid="2762241247228983754">"रंग"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"सभी"</item>
<item msgid="6812869625222503603">"सीमा"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"फ़ाइल पर नहीं लिखा जा सका"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"प्रिंट कार्य जनरेट नहीं किया जा सका"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"पुनः प्रयास करें"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"प्रिंटर अनुपलब्ध है"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"रद्द किया जा रहा है..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index 7182cf6..215c46b 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Postavke pisača"</string>
- <string name="print_button" msgid="645164566271246268">"Ispis"</string>
- <string name="save_button" msgid="1921310454071758999">"Spremi"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Više opcija"</string>
<string name="label_destination" msgid="9132510997381599275">"Odredište"</string>
<string name="label_copies" msgid="3634531042822968308">"Kopije"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Veličina papira"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Kopije:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Veličina papira"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Veličina papira:"</string>
<string name="label_color" msgid="1108690305218188969">"U boji"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orijentacija"</string>
<string name="label_pages" msgid="6300874667546617333">"Stranice (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nema veze s pisačem"</string>
<string name="reason_unknown" msgid="5507940196503246139">"nepoznato"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – zadatak nije dostupan"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Zadatak ispisa nije generiran"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Crno-bijelo"</item>
<item msgid="2762241247228983754">"U boji"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Sve"</item>
<item msgid="6812869625222503603">"Raspon"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Zapisivanje u datoteku nije uspjelo"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Zadatak ispisa nije generiran"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Pokušajte ponovno"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Pisač nije dostupan"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Otkazivanje…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index 6a0741b..314025d 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Nyomtatásisor-kezelő"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Nyomtatóbeállítások"</string>
- <string name="print_button" msgid="645164566271246268">"Nyomtatás"</string>
- <string name="save_button" msgid="1921310454071758999">"Mentés"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"További lehetőségek"</string>
<string name="label_destination" msgid="9132510997381599275">"Cél"</string>
<string name="label_copies" msgid="3634531042822968308">"Példányszám"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Papírméret"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Példányszám:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Papírméret"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Papírméret:"</string>
<string name="label_color" msgid="1108690305218188969">"Szín"</string>
<string name="label_orientation" msgid="2853142581990496477">"Tájolás"</string>
<string name="label_pages" msgid="6300874667546617333">"Oldalszám (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nincs kapcsolat a nyomtatóval"</string>
<string name="reason_unknown" msgid="5507940196503246139">"ismeretlen"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nem érhető el"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Nem sikerült létrehozni a nyomtatási feladatot."</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Fekete-fehér"</item>
<item msgid="2762241247228983754">"Szín"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Összes"</item>
<item msgid="6812869625222503603">"Tartomány"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Nem sikerült írni a fájlba"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Nem sikerült létrehozni a nyomtatási feladatot."</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Újra"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"A nyomtató nem érhető el"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Megszakítás..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index 1423b82..de5c2bfb 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Տպման կարգավար"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Տպիչի կարգավորումներ"</string>
- <string name="print_button" msgid="645164566271246268">"Տպել"</string>
- <string name="save_button" msgid="1921310454071758999">"Պահել"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Այլ ընտրանքներ"</string>
<string name="label_destination" msgid="9132510997381599275">"Նպատակակետ"</string>
<string name="label_copies" msgid="3634531042822968308">"Պատճեններ"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Թղթի չափը"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Պատճեններ՝"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Թղթի չափը"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Թղթի չափը՝"</string>
<string name="label_color" msgid="1108690305218188969">"Գույնը"</string>
<string name="label_orientation" msgid="2853142581990496477">"Դիրքավորում"</string>
<string name="label_pages" msgid="6300874667546617333">"Էջեր (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Տպիչի հետ կապ չկա"</string>
<string name="reason_unknown" msgid="5507940196503246139">"անհայտ"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> տպիչն անհասանելի է"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Չկարողացանք մշակել տպման աշխատանքը"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Սև ու սպիտակ"</item>
<item msgid="2762241247228983754">"Գույնը"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Բոլորը"</item>
<item msgid="6812869625222503603">"Միջակայք"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Հնարավոր չէ գրել ֆայլում"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Չկարողացանք մշակել տպման աշխատանքը"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Կրկնել"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Տպիչն անհասանելի է"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Չեղարկվում է..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index 2b80d07..77180c4 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Setelan printer"</string>
- <string name="print_button" msgid="645164566271246268">"Cetak"</string>
- <string name="save_button" msgid="1921310454071758999">"Simpan"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Opsi lainnya"</string>
<string name="label_destination" msgid="9132510997381599275">"Tujuan"</string>
<string name="label_copies" msgid="3634531042822968308">"Salinan"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Ukuran Kertas"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Salinan:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Ukuran kertas"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Ukuran kertas:"</string>
<string name="label_color" msgid="1108690305218188969">"Warna"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientasi"</string>
<string name="label_pages" msgid="6300874667546617333">"(<xliff:g id="PAGE_COUNT">%1$s</xliff:g>) halaman"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Tidak ada sambungan ke printer"</string>
<string name="reason_unknown" msgid="5507940196503246139">"tak diketahui"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – tidak tersedia"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Tidak dapat membuat tugas cetak"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Hitam & Putih"</item>
<item msgid="2762241247228983754">"Warna"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Semua"</item>
<item msgid="6812869625222503603">"Rentang"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Tidak dapat menulis ke file"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Tidak dapat membuat tugas cetak"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Coba lagi"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Printer tidak tersedia"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Membatalkan…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index 96c3b48..f0ef878 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Impostazioni stampante"</string>
- <string name="print_button" msgid="645164566271246268">"Stampa"</string>
- <string name="save_button" msgid="1921310454071758999">"Salva"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Altre opzioni"</string>
<string name="label_destination" msgid="9132510997381599275">"Destinazione"</string>
<string name="label_copies" msgid="3634531042822968308">"Copie"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Formato carta"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Copie:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Dimensioni carta"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Dimensioni carta:"</string>
<string name="label_color" msgid="1108690305218188969">"A colori"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientamento"</string>
<string name="label_pages" msgid="6300874667546617333">"Pagine (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nessun collegamento alla stampante"</string>
<string name="reason_unknown" msgid="5507940196503246139">"sconosciuto"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - non disponibile"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Impossibile generare processo di stampa"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Bianco e nero"</item>
<item msgid="2762241247228983754">"A colori"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Tutte"</item>
<item msgid="6812869625222503603">"Intervallo"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Impossibile scrivere sul file"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Impossibile generare processo di stampa"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Riprova"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Stampante non disponibile"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Annullamento in corso…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index 3e0e732..e69221a 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"הגדרות מדפסת"</string>
- <string name="print_button" msgid="645164566271246268">"הדפס"</string>
- <string name="save_button" msgid="1921310454071758999">"שמור"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"עוד אפשרויות"</string>
<string name="label_destination" msgid="9132510997381599275">"יעד"</string>
<string name="label_copies" msgid="3634531042822968308">"עותקים"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"גודל נייר"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"עותקים:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"גודל נייר"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"גודל נייר:"</string>
<string name="label_color" msgid="1108690305218188969">"צבע"</string>
<string name="label_orientation" msgid="2853142581990496477">"כיוון"</string>
<string name="label_pages" msgid="6300874667546617333">"עמודים (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"אין חיבור למדפסת"</string>
<string name="reason_unknown" msgid="5507940196503246139">"לא ידוע"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – לא זמינה"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"לא ניתן היה ליצור את עבודת ההדפסה"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"שחור ולבן"</item>
<item msgid="2762241247228983754">"צבע"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"הכל"</item>
<item msgid="6812869625222503603">"טווח"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"לא ניתן היה לכתוב לקובץ"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"לא ניתן היה ליצור את עבודת ההדפסה"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"נסה שוב"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"המדפסת אינה זמינה"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"מבטל…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index d3f4f85..4cc6466 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"印刷スプーラ"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"プリンタの設定"</string>
- <string name="print_button" msgid="645164566271246268">"印刷"</string>
- <string name="save_button" msgid="1921310454071758999">"保存"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"その他のオプション"</string>
<string name="label_destination" msgid="9132510997381599275">"印刷先"</string>
<string name="label_copies" msgid="3634531042822968308">"部数"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"用紙サイズ"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"部数:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"用紙サイズ"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"用紙サイズ:"</string>
<string name="label_color" msgid="1108690305218188969">"カラー選択"</string>
<string name="label_orientation" msgid="2853142581990496477">"方向"</string>
<string name="label_pages" msgid="6300874667546617333">"ページ(<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"プリンタに接続されていません"</string>
<string name="reason_unknown" msgid="5507940196503246139">"不明"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>–使用不可"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"印刷ジョブを生成できませんでした"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"モノクロ"</item>
<item msgid="2762241247228983754">"カラー"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"すべて"</item>
<item msgid="6812869625222503603">"範囲"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"ファイルに書き込めませんでした"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"印刷ジョブを生成できませんでした"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"再試行"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"プリンタを使用できません"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"キャンセルしています…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index d36b7c9..87a1711 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"ბეჭდვის Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"პრინტერის პარამეტრები"</string>
- <string name="print_button" msgid="645164566271246268">"ბეჭდვა"</string>
- <string name="save_button" msgid="1921310454071758999">"შენახვა"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"მეტი ვარიანტები"</string>
<string name="label_destination" msgid="9132510997381599275">"დანიშნულება"</string>
<string name="label_copies" msgid="3634531042822968308">"ასლები"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"ფურცლის ზომა"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"ასლები:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"ფურცლის ზომა"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"ფურცლის ზომა:"</string>
<string name="label_color" msgid="1108690305218188969">"ფერი"</string>
<string name="label_orientation" msgid="2853142581990496477">"ორიენტაცია"</string>
<string name="label_pages" msgid="6300874667546617333">"გვერდები (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"პრინტერთან კავშირი არ არის"</string>
<string name="reason_unknown" msgid="5507940196503246139">"უცნობი"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – მიუწვდომელია"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"ბეჭდვის დავალების გენერაცია ვერ ხერხდება"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"შავ-თეთრი"</item>
<item msgid="2762241247228983754">"ფერი"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"ყველა"</item>
<item msgid="6812869625222503603">"დიაპაზონი"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"ფაილში ჩაწერა ვერ მოხერხდა"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"ბეჭდვის დავალების გენერაცია ვერ ხერხდება"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"გამეორება"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"პრინტერი მიუწვდომელია"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"უქმდება…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index ba3c042..cdcb21f 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"បោះពុម្ពស្ពូល័រ"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"ការកំណត់ម៉ាស៊ីនបោះពុម្ព"</string>
- <string name="print_button" msgid="645164566271246268">"បោះពុម្ព"</string>
- <string name="save_button" msgid="1921310454071758999">"រក្សាទុក"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"ជម្រើសច្រើនទៀត"</string>
<string name="label_destination" msgid="9132510997381599275">"ទិសដៅ"</string>
<string name="label_copies" msgid="3634531042822968308">"ច្បាប់ចម្លង"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"ទំហំក្រដាស"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"ច្បាប់ចម្លង៖"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"ទំហំក្រដាស"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"ទំហំក្រដាស៖"</string>
<string name="label_color" msgid="1108690305218188969">"ពណ៌"</string>
<string name="label_orientation" msgid="2853142581990496477">"ទិស"</string>
<string name="label_pages" msgid="6300874667546617333">"ទំព័រ (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"គ្មានការភ្ជាប់ទៅម៉ាស៊ីនបោះពុម្ព"</string>
<string name="reason_unknown" msgid="5507940196503246139">"មិនស្គាល់"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – មិនអាចប្រើបាន"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"មិនអាចបង្កើតការងារបោះពុម្ព"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"ស & ខ្មៅ"</item>
<item msgid="2762241247228983754">"ពណ៌"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"ទាំងអស់"</item>
<item msgid="6812869625222503603">"ជួរ"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"មិនអាចសរសេរទៅកាន់ឯកសារ"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"មិនអាចបង្កើតការងារបោះពុម្ព"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"ព្យាយាមម្ដងទៀត"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"ម៉ាស៊ីនបោះពុម្ពមិនអាចប្រើបាន"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"កំពុងបោះបង់..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index 3b2fef7..65df4fb 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"인쇄 스풀러"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"프린터 설정"</string>
- <string name="print_button" msgid="645164566271246268">"인쇄"</string>
- <string name="save_button" msgid="1921310454071758999">"저장"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"옵션 더보기"</string>
<string name="label_destination" msgid="9132510997381599275">"대상"</string>
<string name="label_copies" msgid="3634531042822968308">"매수"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"용지 크기"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"매수:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"용지 크기"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"용지 크기:"</string>
<string name="label_color" msgid="1108690305218188969">"색상"</string>
<string name="label_orientation" msgid="2853142581990496477">"방향"</string>
<string name="label_pages" msgid="6300874667546617333">"페이지 수(<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"프린터와 연결되지 않음"</string>
<string name="reason_unknown" msgid="5507940196503246139">"알 수 없음"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – 사용할 수 없음"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"인쇄 작업을 생성할 수 없습니다."</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"흑백"</item>
<item msgid="2762241247228983754">"컬러"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"모두"</item>
<item msgid="6812869625222503603">"범위"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"PDF 파일을 생성하지 못했습니다."</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"인쇄 작업을 생성할 수 없습니다."</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"다시 시도"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"선택한 프린터를 사용할 수 없음"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"취소 중..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-land/constants.xml b/packages/PrintSpooler/res/values-land/constants.xml
index d68b77e..0db7513 100644
--- a/packages/PrintSpooler/res/values-land/constants.xml
+++ b/packages/PrintSpooler/res/values-land/constants.xml
@@ -18,5 +18,6 @@
<dimen name="printer_list_view_padding_start">48dip</dimen>
<dimen name="printer_list_view_padding_end">48dip</dimen>
+ <integer name="print_option_column_count">3</integer>
</resources>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index f954606..d06660c 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"ຕົວຈັດຄິວການພິມ"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"ການຕັ້ງຄ່າເຄື່ອງພິມ"</string>
- <string name="print_button" msgid="645164566271246268">"ພິມ"</string>
- <string name="save_button" msgid="1921310454071758999">"ບັນທຶກ"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"ໂຕເລືອກເພີ່ມເຕີມ"</string>
<string name="label_destination" msgid="9132510997381599275">"ປາຍທາງ"</string>
<string name="label_copies" msgid="3634531042822968308">"ສຳເນົາ"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"ຂະໜາດຂອງໜ້າເຈ້ຍ"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"ຈຳນວນສຳເນົາ:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"ຂະໜາດເຈ້ຍ"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"ຂະໜາດເຈ້ຍ:"</string>
<string name="label_color" msgid="1108690305218188969">"ສີ"</string>
<string name="label_orientation" msgid="2853142581990496477">"ລວງ"</string>
<string name="label_pages" msgid="6300874667546617333">"(<xliff:g id="PAGE_COUNT">%1$s</xliff:g>) ໜ້າ"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"ບໍ່ມີການເຊື່ອມຕໍ່ຫາເຄື່ອງພິມ"</string>
<string name="reason_unknown" msgid="5507940196503246139">"ບໍ່ຮູ້ຈັກ"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - ບໍ່ມີຢູ່"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"ບໍ່ສາມາດສ້າງວຽກພິມໄດ້"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"ຂາວດຳ"</item>
<item msgid="2762241247228983754">"ສີ"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"ທັງໝົດ"</item>
<item msgid="6812869625222503603">"ໄລຍະ"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"ບໍ່ສາມາດຂຽນໄຟລ໌ໄດ້"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"ບໍ່ສາມາດສ້າງວຽກພິມໄດ້"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"ລອງໃໝ່"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"ເຄື່ອງພິມບໍ່ສາມາດໃຊ້ໄດ້"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"ກຳລັງຍົກເລີກ…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index 0c4e386..a42bdd9 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Spausdintuvo nustatymai"</string>
- <string name="print_button" msgid="645164566271246268">"Spausdinti"</string>
- <string name="save_button" msgid="1921310454071758999">"Išsaugoti"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Daugiau parinkčių"</string>
<string name="label_destination" msgid="9132510997381599275">"Paskirties vieta"</string>
<string name="label_copies" msgid="3634531042822968308">"Kopijos"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Popieriaus dydis"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Kopijų:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Popieriaus dydis"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Popieriaus dydis:"</string>
<string name="label_color" msgid="1108690305218188969">"Spalva"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientacija"</string>
<string name="label_pages" msgid="6300874667546617333">"Puslapiai (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nėra ryšio su spausdintuvu"</string>
<string name="reason_unknown" msgid="5507940196503246139">"nežinoma"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"„<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“ – nepasiekiama"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Nepavyko sukurti spausdinimo užduoties"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Nespalvotas"</item>
<item msgid="2762241247228983754">"Spalva"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Visi"</item>
<item msgid="6812869625222503603">"Diapazonas"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Nepavyko įrašyti į failą"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Nepavyko sukurti spausdinimo užduoties"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Bandykite dar kartą"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Spausdintuvas nepasiekiamas"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Atšaukiama…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index 3fffdfe..3afba54 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Printera iestatījumi"</string>
- <string name="print_button" msgid="645164566271246268">"Drukāt"</string>
- <string name="save_button" msgid="1921310454071758999">"Saglabāt"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Citas opcijas"</string>
<string name="label_destination" msgid="9132510997381599275">"Galamērķis"</string>
<string name="label_copies" msgid="3634531042822968308">"Eksemplāri"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Papīra izmērs"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Eksemplāri:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Papīra izmērs"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Papīra izmērs:"</string>
<string name="label_color" msgid="1108690305218188969">"Krāsa"</string>
<string name="label_orientation" msgid="2853142581990496477">"Virziens"</string>
<string name="label_pages" msgid="6300874667546617333">"Lapas (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nav savienojuma ar printeri"</string>
<string name="reason_unknown" msgid="5507940196503246139">"nezināms"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> — nav pieejams"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Nevarēja ģenerēt drukas darbu"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Melnbalts"</item>
<item msgid="2762241247228983754">"Krāsa"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Visi"</item>
<item msgid="6812869625222503603">"Diapazons"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Nevarēja ierakstīt failā."</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Nevarēja ģenerēt drukas darbu"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Mēģināt vēlreiz"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Printeris nav pieejams."</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Notiek atcelšana…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index e429387..ffe98fe 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Хэвлэгчийн буфер"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Принтерийн тохиргоо"</string>
- <string name="print_button" msgid="645164566271246268">"Хэвлэх"</string>
- <string name="save_button" msgid="1921310454071758999">"Хадгалах"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Нэмэлт сонголтууд"</string>
<string name="label_destination" msgid="9132510997381599275">"Хүлээн авагч"</string>
<string name="label_copies" msgid="3634531042822968308">"Хуулбарууд"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Цаасны хэмжээ"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Хуулбар:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Цаасны хэмжээ"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Цаасны хэмжээ:"</string>
<string name="label_color" msgid="1108690305218188969">"Өнгө"</string>
<string name="label_orientation" msgid="2853142581990496477">"Чиглэл"</string>
<string name="label_pages" msgid="6300874667546617333">"(<xliff:g id="PAGE_COUNT">%1$s</xliff:g>) хуудас"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Принтер холбогдоогүй байна"</string>
<string name="reason_unknown" msgid="5507940196503246139">"тодорхойгүй"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ашиглах боломжгүй"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Хэвлэх ажлыг үүсгэж чадсангүй"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Хар & Цагаан"</item>
<item msgid="2762241247228983754">"Өнгө"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Бүгд"</item>
<item msgid="6812869625222503603">"Хүрээ"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Файл руу бичиж чадсангүй"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Хэвлэх ажлыг үүсгэж чадсангүй"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Дахин оролдох"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Принтер байхгүй"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Цуцлаж байна..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index cca5d2c..7141aeb 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Penspul Cetakan"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Tetapan pencetak"</string>
- <string name="print_button" msgid="645164566271246268">"Cetak"</string>
- <string name="save_button" msgid="1921310454071758999">"Simpan"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Lagi pilihan"</string>
<string name="label_destination" msgid="9132510997381599275">"Destinasi"</string>
<string name="label_copies" msgid="3634531042822968308">"Salinan"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Saiz Kertas"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Salinan:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Saiz kertas"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Saiz kertas:"</string>
<string name="label_color" msgid="1108690305218188969">"Warna"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientasi"</string>
<string name="label_pages" msgid="6300874667546617333">"Halaman (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Tiada sambungan ke pencetak"</string>
<string name="reason_unknown" msgid="5507940196503246139">"tidak diketahui"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – tidak tersedia"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Tidak dapat menjana kerja cetakan"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Hitam & Putih"</item>
<item msgid="2762241247228983754">"Warna"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Semua"</item>
<item msgid="6812869625222503603">"Julat"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Tidak dapat menulis ke fail"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Tidak dapat menjana kerja cetakan"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Cuba semula"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Pencetak tidak tersedia"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Membatalkan..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index f6a60c6..8c66bfb 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Utskriftskø"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Skriverinnstillinger"</string>
- <string name="print_button" msgid="645164566271246268">"Skriv ut"</string>
- <string name="save_button" msgid="1921310454071758999">"Lagre"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Flere alternativer"</string>
<string name="label_destination" msgid="9132510997381599275">"Destinasjon"</string>
<string name="label_copies" msgid="3634531042822968308">"Kopier"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Papirstørrelse"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Kopier:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Papirstørrelse"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Papirstørrelse:"</string>
<string name="label_color" msgid="1108690305218188969">"Farge"</string>
<string name="label_orientation" msgid="2853142581990496477">"Retning"</string>
<string name="label_pages" msgid="6300874667546617333">"Sider (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen forbindelse med skriveren"</string>
<string name="reason_unknown" msgid="5507940196503246139">"ukjent"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – utilgjengelig"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Kunne ikke generere utskriftsjobben"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Svart og hvitt"</item>
<item msgid="2762241247228983754">"Farge"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Alle"</item>
<item msgid="6812869625222503603">"Område"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Kunne ikke skrive til filen"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Kunne ikke generere utskriftsjobben"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Prøv på nytt"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Skriveren er utilgjengelig"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Avbryter …"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index dc12508..caa5c80 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Afdrukspooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Printerinstellingen"</string>
- <string name="print_button" msgid="645164566271246268">"Afdrukken"</string>
- <string name="save_button" msgid="1921310454071758999">"Opslaan"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Meer opties"</string>
<string name="label_destination" msgid="9132510997381599275">"Bestemming"</string>
<string name="label_copies" msgid="3634531042822968308">"Aantal exemplaren"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Papierformaat"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Aantal:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Papierformaat"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Papierformaat:"</string>
<string name="label_color" msgid="1108690305218188969">"Kleur"</string>
<string name="label_orientation" msgid="2853142581990496477">"Stand"</string>
<string name="label_pages" msgid="6300874667546617333">"Pagina\'s (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Geen verbinding met printer"</string>
<string name="reason_unknown" msgid="5507940196503246139">"onbekend"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – niet beschikbaar"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Kan de afdruktaak niet genereren"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Zwart-wit"</item>
<item msgid="2762241247228983754">"Kleur"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Alle"</item>
<item msgid="6812869625222503603">"Bereik"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Kan niet naar bestand schrijven"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Kan de afdruktaak niet genereren"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Opnieuw proberen"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Printer niet beschikbaar"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Annuleren…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index 81acc76..d19f2ac 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Bufor wydruku"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Ustawienia drukarki"</string>
- <string name="print_button" msgid="645164566271246268">"Drukuj"</string>
- <string name="save_button" msgid="1921310454071758999">"Zapisz"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Więcej opcji"</string>
<string name="label_destination" msgid="9132510997381599275">"Miejsce docelowe"</string>
<string name="label_copies" msgid="3634531042822968308">"Kopie"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Rozmiar papieru"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Kopie:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Rozmiar papieru"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Rozmiar papieru:"</string>
<string name="label_color" msgid="1108690305218188969">"Kolor"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientacja"</string>
<string name="label_pages" msgid="6300874667546617333">"Strony (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Brak połączenia z drukarką"</string>
<string name="reason_unknown" msgid="5507940196503246139">"brak informacji"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – niedostępne"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Nie udało się wygenerować zadania drukowania"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Czarno-białe"</item>
<item msgid="2762241247228983754">"Kolor"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Wszystkie"</item>
<item msgid="6812869625222503603">"Zakres"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Nie można zapisać pliku"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Nie udało się wygenerować zadania drukowania"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Ponów próbę"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Drukarka niedostępna"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Anuluję…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 6bfc395..6970730 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Definições da impressora"</string>
- <string name="print_button" msgid="645164566271246268">"Imprimir"</string>
- <string name="save_button" msgid="1921310454071758999">"Guardar"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Mais opções"</string>
<string name="label_destination" msgid="9132510997381599275">"Destino"</string>
<string name="label_copies" msgid="3634531042822968308">"Cópias"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Tamanho do papel"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Cópias:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Tamanho do papel"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Tamanho do papel:"</string>
<string name="label_color" msgid="1108690305218188969">"Cor"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientação"</string>
<string name="label_pages" msgid="6300874667546617333">"Páginas (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Sem ligação à impressora"</string>
<string name="reason_unknown" msgid="5507940196503246139">"desconhecido"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – indisponível"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Não foi possível gerar a tarefa de impressão"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Preto e branco"</item>
<item msgid="2762241247228983754">"Cor"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Todas"</item>
<item msgid="6812869625222503603">"Intervalo"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Não foi possível gravar no ficheiro"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Não foi possível gerar a tarefa de impressão"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Tentar novamente"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Impressora não disponível"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"A cancelar…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index 82c157d..8b2a6fb 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Sp. de impressão"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Configur. da impressora"</string>
- <string name="print_button" msgid="645164566271246268">"Imprimir"</string>
- <string name="save_button" msgid="1921310454071758999">"Salvar"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Mais opções"</string>
<string name="label_destination" msgid="9132510997381599275">"Destino"</string>
<string name="label_copies" msgid="3634531042822968308">"Cópias"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Tamanho do papel"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Cópias:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Tamanho do papel"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Tamanho do papel:"</string>
<string name="label_color" msgid="1108690305218188969">"Cor"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientação"</string>
<string name="label_pages" msgid="6300874667546617333">"Páginas (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Sem conexão com a impressora"</string>
<string name="reason_unknown" msgid="5507940196503246139">"desconhecido"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – não disponível"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Não foi possível gerar o trabalho de impressão"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Preto e branco"</item>
<item msgid="2762241247228983754">"Cor"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Todas"</item>
<item msgid="6812869625222503603">"Intervalo"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Não foi possível gravar no arquivo"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Não foi possível gerar o trabalho de impressão"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Tentar novamente"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Impressora indisponível"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Cancelando..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index 79c3bdc..6706cf6 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Derulator print."</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Setările imprimantei"</string>
- <string name="print_button" msgid="645164566271246268">"Printați"</string>
- <string name="save_button" msgid="1921310454071758999">"Salvați"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Mai multe opțiuni"</string>
<string name="label_destination" msgid="9132510997381599275">"Destinație"</string>
<string name="label_copies" msgid="3634531042822968308">"Copii"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Formatul hârtiei"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Copii:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Formatul hârtiei"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Formatul hârtiei:"</string>
<string name="label_color" msgid="1108690305218188969">"Color"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientare"</string>
<string name="label_pages" msgid="6300874667546617333">"Pagini (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Nu există conexiune la o imprimantă"</string>
<string name="reason_unknown" msgid="5507940196503246139">"necunoscut"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - indisponibil"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Nu s-a putut genera sarcina de printare"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Alb-negru"</item>
<item msgid="2762241247228983754">"Color"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Toate"</item>
<item msgid="6812869625222503603">"Interval"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Nu s-a putut scrie în fișier."</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Nu s-a putut genera sarcina de printare"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Reîncercați"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Imprimanta nu este disponibilă"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"În curs de anulare..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index a27f3c8..2256be4 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Спулер печати"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Настройки принтера"</string>
- <string name="print_button" msgid="645164566271246268">"Печать"</string>
- <string name="save_button" msgid="1921310454071758999">"Сохранить"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Ещё"</string>
<string name="label_destination" msgid="9132510997381599275">"Принтер"</string>
<string name="label_copies" msgid="3634531042822968308">"Копии"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Формат"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Копии:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Размер бумаги"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Размер бумаги:"</string>
<string name="label_color" msgid="1108690305218188969">"Печать"</string>
<string name="label_orientation" msgid="2853142581990496477">"Ориентация"</string>
<string name="label_pages" msgid="6300874667546617333">"СТРАНИЦЫ (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Нет связи с принтером"</string>
<string name="reason_unknown" msgid="5507940196503246139">"неизвестно"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – недоступен"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Не удалось отправить документ на печать."</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Черно-белая"</item>
<item msgid="2762241247228983754">"Цветная"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Все"</item>
<item msgid="6812869625222503603">"Диапазон"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Не удалось записать в файл"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Не удалось отправить документ на печать."</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Повторить"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Принтер недоступен"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Отмена…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 39a022d..a4f0444 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Zaraďovač tlače"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Nastavenia tlačiarne"</string>
- <string name="print_button" msgid="645164566271246268">"Tlačiť"</string>
- <string name="save_button" msgid="1921310454071758999">"Uložiť"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Ďalšie možnosti"</string>
<string name="label_destination" msgid="9132510997381599275">"Cieľ"</string>
<string name="label_copies" msgid="3634531042822968308">"Kópie"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Veľkosť papiera"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Počet kópií:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Veľkosť papiera"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Veľkosť papiera:"</string>
<string name="label_color" msgid="1108690305218188969">"Farba"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientácia"</string>
<string name="label_pages" msgid="6300874667546617333">"STRÁNKY (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Žiadne pripojenie k tlačiarni"</string>
<string name="reason_unknown" msgid="5507940196503246139">"neznáme"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nie je k dispozícii"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Tlačovú úlohu nie je možné vytvoriť"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Čiernobiele"</item>
<item msgid="2762241247228983754">"Farba"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Všetky"</item>
<item msgid="6812869625222503603">"Rozsah"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Do súboru nie je možné zapisovať"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Tlačovú úlohu nie je možné vytvoriť"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Opakovať"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Tlačiareň nie je k dispozícii"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Ruší sa..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index e299508..672af526 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Tisk. v ozadju"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Nastavitve tiskalnika"</string>
- <string name="print_button" msgid="645164566271246268">"Natisni"</string>
- <string name="save_button" msgid="1921310454071758999">"Shrani"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Več možnosti"</string>
<string name="label_destination" msgid="9132510997381599275">"Cilj"</string>
<string name="label_copies" msgid="3634531042822968308">"Št. kopij"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Velikost papirja"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Št. kopij:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Velikost papirja"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Velikost papirja:"</string>
<string name="label_color" msgid="1108690305218188969">"Barvno"</string>
<string name="label_orientation" msgid="2853142581990496477">"Postavitev"</string>
<string name="label_pages" msgid="6300874667546617333">"Št. strani (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Ni povezave s tiskalnikom"</string>
<string name="reason_unknown" msgid="5507940196503246139">"neznano"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ni na voljo"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Tiskalnega opravila ni bilo mogoče ustvariti"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Črno-belo"</item>
<item msgid="2762241247228983754">"Barvno"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Vse"</item>
<item msgid="6812869625222503603">"Obseg"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"V datoteko ni bilo mogoče zapisovati"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Tiskalnega opravila ni bilo mogoče ustvariti"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Poskusi znova"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Tiskalnik ni na voljo"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Preklic …"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index cbab1a6..ad45a93 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Штамп. из мемор."</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Подешавања штампача"</string>
- <string name="print_button" msgid="645164566271246268">"Штампај"</string>
- <string name="save_button" msgid="1921310454071758999">"Сачувај"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Још опција"</string>
<string name="label_destination" msgid="9132510997381599275">"Одредиште"</string>
<string name="label_copies" msgid="3634531042822968308">"Копије"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Величина папира"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Копије:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Величина папира"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Величина папира:"</string>
<string name="label_color" msgid="1108690305218188969">"Боја"</string>
<string name="label_orientation" msgid="2853142581990496477">"Положај"</string>
<string name="label_pages" msgid="6300874667546617333">"Странице (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Нема везе са штампачем"</string>
<string name="reason_unknown" msgid="5507940196503246139">"непознато"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – недоступан"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Није могуће генерисати задатак за штампање"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Црно-бело"</item>
<item msgid="2762241247228983754">"Боја"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Све"</item>
<item msgid="6812869625222503603">"Опсег"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Уписивање у датотеку није могуће"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Није могуће генерисати задатак за штампање"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Покушајте поново"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Штампач није доступан"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Отказивање..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index 2286fce..a777165 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Utskriftskö"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Skrivarinställningar"</string>
- <string name="print_button" msgid="645164566271246268">"Skriv ut"</string>
- <string name="save_button" msgid="1921310454071758999">"Spara"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Fler alternativ"</string>
<string name="label_destination" msgid="9132510997381599275">"Destination"</string>
<string name="label_copies" msgid="3634531042822968308">"Kopior"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Pappersstorlek"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Kopior:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Pappersstorlek"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Pappersstorlek:"</string>
<string name="label_color" msgid="1108690305218188969">"Färg"</string>
<string name="label_orientation" msgid="2853142581990496477">"Orientering"</string>
<string name="label_pages" msgid="6300874667546617333">"Sidor (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Ingen anslutning till skrivaren"</string>
<string name="reason_unknown" msgid="5507940196503246139">"okänt"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – inte tillgänglig"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Det gick inte att skapa utskriftsjobbet"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Svartvit"</item>
<item msgid="2762241247228983754">"Färg"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Alla"</item>
<item msgid="6812869625222503603">"Intervall"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Det gick inte att skriva till filen"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Det gick inte att skapa utskriftsjobbet"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Försök igen"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Skrivaren är inte tillgänglig"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Avbryter ..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index a84e9b3..4c7b3c3 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Programu ya kuandaa Printa kwa ajili ya Kuchapisha"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Mipangilio ya printa"</string>
- <string name="print_button" msgid="645164566271246268">"Chapisha"</string>
- <string name="save_button" msgid="1921310454071758999">"Hifadhi"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Chaguo zaidi"</string>
<string name="label_destination" msgid="9132510997381599275">"Itakapofika"</string>
<string name="label_copies" msgid="3634531042822968308">"Nakala"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Ukubwa wa Karatasi"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Nakala:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Ukubwa wa karatasi"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Ukubwa wa karatasi:"</string>
<string name="label_color" msgid="1108690305218188969">"Rangi"</string>
<string name="label_orientation" msgid="2853142581990496477">"Mkao"</string>
<string name="label_pages" msgid="6300874667546617333">"Kurasa (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Hakuna muunganisho kwa printa"</string>
<string name="reason_unknown" msgid="5507940196503246139">"haijulikani"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - haipatikani"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Haikuweza kuleta kazi ya kuchapisha"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Nyeusi na Nyeupe"</item>
<item msgid="2762241247228983754">"Rangi"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Zote"</item>
<item msgid="6812869625222503603">"Masafa"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Haikuweza kuandika kwenye faili"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Haikuweza kuleta kazi ya kuchapisha"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Jaribu tena"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Printa haipatikani"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Inaghairi..."</string>
</resources>
diff --git a/core/res/res/drawable/item_background_borderless_quantum.xml b/packages/PrintSpooler/res/values-sw600dp-land/constants.xml
similarity index 81%
copy from core/res/res/drawable/item_background_borderless_quantum.xml
copy to packages/PrintSpooler/res/values-sw600dp-land/constants.xml
index c2a1c127..cacdf98 100644
--- a/core/res/res/drawable/item_background_borderless_quantum.xml
+++ b/packages/PrintSpooler/res/values-sw600dp-land/constants.xml
@@ -14,6 +14,8 @@
limitations under the License.
-->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:tint="?attr/colorControlHighlight"
- android:pinned="true" />
+<resources>
+
+ <integer name="print_option_column_count">6</integer>
+
+</resources>
diff --git a/core/res/res/drawable/item_background_borderless_quantum.xml b/packages/PrintSpooler/res/values-sw600dp/constants.xml
similarity index 74%
copy from core/res/res/drawable/item_background_borderless_quantum.xml
copy to packages/PrintSpooler/res/values-sw600dp/constants.xml
index c2a1c127..14c099c 100644
--- a/core/res/res/drawable/item_background_borderless_quantum.xml
+++ b/packages/PrintSpooler/res/values-sw600dp/constants.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2013 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,6 +14,8 @@
limitations under the License.
-->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:tint="?attr/colorControlHighlight"
- android:pinned="true" />
+<resources>
+
+ <integer name="print_option_column_count">3</integer>
+
+</resources>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index aa01d6f..e3e09d3 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"การตั้งค่าเครื่องพิมพ์"</string>
- <string name="print_button" msgid="645164566271246268">"พิมพ์"</string>
- <string name="save_button" msgid="1921310454071758999">"บันทึก"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"ตัวเลือกอื่น"</string>
<string name="label_destination" msgid="9132510997381599275">"ปลายทาง"</string>
<string name="label_copies" msgid="3634531042822968308">"สำเนา"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"ขนาดของกระดาษ"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"สำเนา:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"ขนาดของกระดาษ"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"ขนาดของกระดาษ:"</string>
<string name="label_color" msgid="1108690305218188969">"สี"</string>
<string name="label_orientation" msgid="2853142581990496477">"การวางแนว"</string>
<string name="label_pages" msgid="6300874667546617333">"หน้า (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"ไม่มีการเชื่อมต่อไปยังเครื่องพิมพ์"</string>
<string name="reason_unknown" msgid="5507940196503246139">"ไม่ทราบ"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ไม่พร้อมใช้งาน"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"ไม่สามารถสร้างงานพิมพ์"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"ขาวดำ"</item>
<item msgid="2762241247228983754">"สี"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"ทั้งหมด"</item>
<item msgid="6812869625222503603">"ช่วง"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"ไม่สามารถเขียนไปยังไฟล์ได้"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"ไม่สามารถสร้างงานพิมพ์"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"ลองอีกครั้ง"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"ไม่สามารถใช้งานเครื่องพิมพ์ได้"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"กำลังยกเลิก…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index a72c937..bb7d0bf 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Mga setting ng printer"</string>
- <string name="print_button" msgid="645164566271246268">"I-print"</string>
- <string name="save_button" msgid="1921310454071758999">"I-save"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Higit pang mga opsyon"</string>
<string name="label_destination" msgid="9132510997381599275">"Patutunguhan"</string>
<string name="label_copies" msgid="3634531042822968308">"Mga Kopya"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Laki ng Papel"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Dami ng kopya:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Laki ng papel"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Laki ng papel:"</string>
<string name="label_color" msgid="1108690305218188969">"Kulay"</string>
<string name="label_orientation" msgid="2853142581990496477">"Oryentasyon"</string>
<string name="label_pages" msgid="6300874667546617333">"Mga Pahina (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Hindi nakakonekta sa printer"</string>
<string name="reason_unknown" msgid="5507940196503246139">"hindi alam"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – hindi available"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Hindi mabuo ang pag-print"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Black & White"</item>
<item msgid="2762241247228983754">"Kulay"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Lahat"</item>
<item msgid="6812869625222503603">"Sakop"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Hindi makapag-write sa file"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Hindi mabuo ang pag-print"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Subukang muli"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Hindi available ang printer"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Kinakansela…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index c6e302d..5f81654 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Yazıcı ayarları"</string>
- <string name="print_button" msgid="645164566271246268">"Yazdır"</string>
- <string name="save_button" msgid="1921310454071758999">"Kaydet"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Diğer seçenekler"</string>
<string name="label_destination" msgid="9132510997381599275">"Hedef"</string>
<string name="label_copies" msgid="3634531042822968308">"Kopya sayısı"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Kağıt Boyutu"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Kopya sayısı"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Kağıt boyutu"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Kağıt boyutu:"</string>
<string name="label_color" msgid="1108690305218188969">"Renkli"</string>
<string name="label_orientation" msgid="2853142581990496477">"Sayfa yönü"</string>
<string name="label_pages" msgid="6300874667546617333">"Sayfa (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Yazıcı bağlantısı yok"</string>
<string name="reason_unknown" msgid="5507940196503246139">"bilinmiyor"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – kullanılamıyor"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Yazdırma işi oluşturulamadı"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Siyah Beyaz"</item>
<item msgid="2762241247228983754">"Renkli"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Tümü"</item>
<item msgid="6812869625222503603">"Aralık"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Dosyaya yazılamadı"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Yazdırma işi oluşturulamadı"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Yeniden dene"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Yazıcı kullanılamıyor"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"İptal ediliyor…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index 4f526d0..81be680 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Налаштування принтера"</string>
- <string name="print_button" msgid="645164566271246268">"Друк"</string>
- <string name="save_button" msgid="1921310454071758999">"Зберегти"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Більше опцій"</string>
<string name="label_destination" msgid="9132510997381599275">"Місце признач-ня"</string>
<string name="label_copies" msgid="3634531042822968308">"Копії"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Розмір паперу"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Копій:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Розмір паперу"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Розмір паперу:"</string>
<string name="label_color" msgid="1108690305218188969">"Колір"</string>
<string name="label_orientation" msgid="2853142581990496477">"Орієнтація"</string>
<string name="label_pages" msgid="6300874667546617333">"Сторінки (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Немає з’єднання з принтером"</string>
<string name="reason_unknown" msgid="5507940196503246139">"невідомо"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" не доступне"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Не вдалося створити завдання друку"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Чорно-білий"</item>
<item msgid="2762241247228983754">"Колір"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Усі"</item>
<item msgid="6812869625222503603">"Діапазон"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Не вдається записати у файл"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Не вдалося створити завдання друку"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Повторити"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Принтер недоступний"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Скасування…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index d21172c..84e97fd 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Print Spooler"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Cài đặt máy in"</string>
- <string name="print_button" msgid="645164566271246268">"In"</string>
- <string name="save_button" msgid="1921310454071758999">"Lưu"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Thêm tùy chọn"</string>
<string name="label_destination" msgid="9132510997381599275">"Đích"</string>
<string name="label_copies" msgid="3634531042822968308">"Bản sao"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Kích thước trang"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Bản sao:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Khổ giấy"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Khổ giấy:"</string>
<string name="label_color" msgid="1108690305218188969">"Màu"</string>
<string name="label_orientation" msgid="2853142581990496477">"Hướng"</string>
<string name="label_pages" msgid="6300874667546617333">"Trang (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Không có kết nối nào với máy in"</string>
<string name="reason_unknown" msgid="5507940196503246139">"không xác định"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – không khả dụng"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Không thể tạo lệnh in"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Đen trắng"</item>
<item msgid="2762241247228983754">"Màu"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Tất cả"</item>
<item msgid="6812869625222503603">"Dãy"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Không thể ghi vào tệp"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Không thể tạo lệnh in"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Thử lại"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Máy in không khả dụng"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Đang hủy…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index e43ea60..a904388 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"打印处理服务"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"打印机设置"</string>
- <string name="print_button" msgid="645164566271246268">"打印"</string>
- <string name="save_button" msgid="1921310454071758999">"保存"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"更多选项"</string>
<string name="label_destination" msgid="9132510997381599275">"目的地"</string>
<string name="label_copies" msgid="3634531042822968308">"份数"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"纸张尺寸"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"份数:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"纸张尺寸"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"纸张尺寸:"</string>
<string name="label_color" msgid="1108690305218188969">"颜色"</string>
<string name="label_orientation" msgid="2853142581990496477">"方向"</string>
<string name="label_pages" msgid="6300874667546617333">"页数 (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"未与打印机建立连接"</string>
<string name="reason_unknown" msgid="5507940196503246139">"未知"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> - 无法使用"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"无法生成打印作业"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"黑白"</item>
<item msgid="2762241247228983754">"彩色"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"全部"</item>
<item msgid="6812869625222503603">"范围"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"无法写入文件"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"无法生成打印作业"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"重试"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"打印机不可用"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"正在取消…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index 2c2422a9..534d4bf 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"列印多工緩衝處理器"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"打印機設定"</string>
- <string name="print_button" msgid="645164566271246268">"列印"</string>
- <string name="save_button" msgid="1921310454071758999">"儲存"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"更多選項"</string>
<string name="label_destination" msgid="9132510997381599275">"目的地"</string>
<string name="label_copies" msgid="3634531042822968308">"份數"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"紙張大小"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"份數:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"紙張大小"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"紙張大小:"</string>
<string name="label_color" msgid="1108690305218188969">"顏色"</string>
<string name="label_orientation" msgid="2853142581990496477">"方向"</string>
<string name="label_pages" msgid="6300874667546617333">"頁數 (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"尚未與打印機連線"</string>
<string name="reason_unknown" msgid="5507940196503246139">"不明"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – 無法使用"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"無法產生列印工作"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"黑白"</item>
<item msgid="2762241247228983754">"彩色"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"全部"</item>
<item msgid="6812869625222503603">"範圍"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"無法寫入檔案"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"無法產生列印工作"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"重試"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"印表機無法使用"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"取消中…"</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index 0fe88d9..95960c4 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"列印多工緩衝處理器"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"印表機設定"</string>
- <string name="print_button" msgid="645164566271246268">"列印"</string>
- <string name="save_button" msgid="1921310454071758999">"儲存"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"更多選項"</string>
<string name="label_destination" msgid="9132510997381599275">"目的地"</string>
<string name="label_copies" msgid="3634531042822968308">"份數"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"紙張大小"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"份數:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"紙張大小"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"紙張大小:"</string>
<string name="label_color" msgid="1108690305218188969">"色彩"</string>
<string name="label_orientation" msgid="2853142581990496477">"方向"</string>
<string name="label_pages" msgid="6300874667546617333">"頁數 (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"尚未與印表機建立連線"</string>
<string name="reason_unknown" msgid="5507940196503246139">"不明"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – 無法使用"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"無法產生列印工作"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"黑白"</item>
<item msgid="2762241247228983754">"彩色"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"全部"</item>
<item msgid="6812869625222503603">"範圍"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"無法寫入檔案"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"無法產生列印工作"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"重試"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"印表機無法使用"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"取消中..."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index 08e31e1..f46d2db9a 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -17,12 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4469836075319831821">"Ispuli sephrinta"</string>
- <string name="advanced_settings_button" msgid="5764225091289415632">"Izilungiselelo zephrinta"</string>
- <string name="print_button" msgid="645164566271246268">"Phrinta"</string>
- <string name="save_button" msgid="1921310454071758999">"Londoloza"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Izinketho eziningi"</string>
<string name="label_destination" msgid="9132510997381599275">"Indawo"</string>
<string name="label_copies" msgid="3634531042822968308">"Amakhophi"</string>
- <string name="label_paper_size" msgid="8681895607876809323">"Usayizi wephepha"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Amakhophi:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Usayizi wekhasi"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Usayizi wekhasi"</string>
<string name="label_color" msgid="1108690305218188969">"Umbala"</string>
<string name="label_orientation" msgid="2853142581990496477">"Umumo"</string>
<string name="label_pages" msgid="6300874667546617333">"Amakhasi (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
@@ -63,7 +63,6 @@
<string name="no_connection_to_printer" msgid="2159246915977282728">"Akukho ukuxhumana kuphrinta"</string>
<string name="reason_unknown" msgid="5507940196503246139">"akwaziwa"</string>
<string name="printer_unavailable" msgid="2434170617003315690">"I-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – ayitholakali"</string>
- <string name="print_error_default_message" msgid="8568506918983980567">"Ayikwazanga ukukhiqiza umsebenzi wokuphrinta"</string>
<string-array name="color_mode_labels">
<item msgid="7602948745415174937">"Okumnyama nokumhlophe"</item>
<item msgid="2762241247228983754">"Umbala"</item>
@@ -76,4 +75,9 @@
<item msgid="7421377442011699994">"Konke"</item>
<item msgid="6812869625222503603">"Ibanga"</item>
</string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Ayikwazanga ukubhala kufayela"</string>
+ <string name="print_error_default_message" msgid="8568506918983980567">"Ayikwazanga ukukhiqiza umsebenzi wokuphrinta"</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Zama futhi"</string>
+ <string name="print_error_printer_unavailable" msgid="6653128543854282851">"Iphrinta ayitholakali"</string>
+ <string name="print_operation_canceling" msgid="5274571823242489160">"Iyakhansela…"</string>
</resources>
diff --git a/core/res/res/drawable/item_background_borderless_quantum.xml b/packages/PrintSpooler/res/values/attrs.xml
similarity index 80%
copy from core/res/res/drawable/item_background_borderless_quantum.xml
copy to packages/PrintSpooler/res/values/attrs.xml
index c2a1c127..feb8be1 100644
--- a/core/res/res/drawable/item_background_borderless_quantum.xml
+++ b/packages/PrintSpooler/res/values/attrs.xml
@@ -14,6 +14,12 @@
limitations under the License.
-->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:tint="?attr/colorControlHighlight"
- android:pinned="true" />
+<resources>
+
+ <declare-styleable name="PrintOptionsLayout">
+
+ <attr name="columnCount" format="integer" />
+
+ </declare-styleable>
+
+</resources>
diff --git a/packages/PrintSpooler/res/values/colors.xml b/packages/PrintSpooler/res/values/colors.xml
index 4fc25b3..fd6ae195 100644
--- a/packages/PrintSpooler/res/values/colors.xml
+++ b/packages/PrintSpooler/res/values/colors.xml
@@ -16,10 +16,6 @@
<resources>
- <color name="container_background">#F2F2F2</color>
- <color name="important_text">#333333</color>
- <color name="print_option_title">#888888</color>
- <color name="separator">#CCCCCC</color>
- <color name="action_button_background">#FFFFFF</color>
+ <color name="print_button_tint_color">#EEFF41</color>
</resources>
diff --git a/packages/PrintSpooler/res/values/constants.xml b/packages/PrintSpooler/res/values/constants.xml
index e9c925c..9a2c14e 100644
--- a/packages/PrintSpooler/res/values/constants.xml
+++ b/packages/PrintSpooler/res/values/constants.xml
@@ -19,6 +19,8 @@
<integer name="page_option_value_all">0</integer>
<integer name="page_option_value_page_range">1</integer>
+ <integer name="print_option_column_count">2</integer>
+
<integer-array name="page_options_values" translatable="false">
<item>@integer/page_option_value_all</item>
<item>@integer/page_option_value_page_range</item>
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index d2613d0..d85529c 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -19,14 +19,8 @@
<!-- Title of the PrintSpooler application. [CHAR LIMIT=50] -->
<string name="app_label">Print Spooler</string>
- <!-- Label of the print dialog's button for advanced printer settings. [CHAR LIMIT=25] -->
- <string name="advanced_settings_button">Printer settings</string>
-
- <!-- Label of the print dialog's print button. [CHAR LIMIT=16] -->
- <string name="print_button">Print</string>
-
- <!-- Label of the print dialog's save button. [CHAR LIMIT=16] -->
- <string name="save_button">Save</string>
+ <!-- Label of the print dialog's button for more print options. [CHAR LIMIT=25] -->
+ <string name="more_options_button">More options</string>
<!-- Label of the destination widget. [CHAR LIMIT=20] -->
<string name="label_destination">Destination</string>
@@ -34,8 +28,14 @@
<!-- Label of the copies count widget. [CHAR LIMIT=20] -->
<string name="label_copies">Copies</string>
+ <!-- Label of the copies count for the print options summary. [CHAR LIMIT=20] -->
+ <string name="label_copies_summary">Copies:</string>
+
<!-- Label of the paper size widget. [CHAR LIMIT=20] -->
- <string name="label_paper_size">Paper Size</string>
+ <string name="label_paper_size">Paper size</string>
+
+ <!-- Label of the paper size for the print options summary. [CHAR LIMIT=20] -->
+ <string name="label_paper_size_summary">Paper size:</string>
<!-- Label of the color mode widget. [CHAR LIMIT=20] -->
<string name="label_color">Color</string>
@@ -118,19 +118,19 @@
<!-- Notifications -->
- <!-- Template for the notificaiton label for a printing print job. [CHAR LIMIT=25] -->
+ <!-- Template for the notification label for a printing print job. [CHAR LIMIT=25] -->
<string name="printing_notification_title_template">Printing <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
- <!-- Template for the notificaiton label for a cancelling print job. [CHAR LIMIT=25] -->
+ <!-- Template for the notification label for a cancelling print job. [CHAR LIMIT=25] -->
<string name="cancelling_notification_title_template">Cancelling <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
- <!-- Template for the notificaiton label for a failed print job. [CHAR LIMIT=25] -->
+ <!-- Template for the notification label for a failed print job. [CHAR LIMIT=25] -->
<string name="failed_notification_title_template">Printer error <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
- <!-- Template for the notificaiton label for a blocked print job. [CHAR LIMIT=25] -->
+ <!-- Template for the notification label for a blocked print job. [CHAR LIMIT=25] -->
<string name="blocked_notification_title_template">Printer blocked <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
- <!-- Template for the notificaiton label for a composite (multiple items) print jobs notification. [CHAR LIMIT=25] -->
+ <!-- Template for the notification label for a composite (multiple items) print jobs notification. [CHAR LIMIT=25] -->
<plurals name="composite_notification_title_template">
<item quantity="one"><xliff:g id="print_job_name" example="foo.jpg">%1$d</xliff:g> print job</item>
<item quantity="other"><xliff:g id="print_job_name" example="foo.jpg">%1$d</xliff:g> print jobs</item>
@@ -139,7 +139,7 @@
<!-- Label for the notification button for cancelling a print job. [CHAR LIMIT=25] -->
<string name="cancel">Cancel</string>
- <!-- Label for the notification button for restrating a filed print job. [CHAR LIMIT=25] -->
+ <!-- Label for the notification button for restarting a filed print job. [CHAR LIMIT=25] -->
<string name="restart">Restart</string>
<!-- Message that there is no connection to a printer. [CHAR LIMIT=40] -->
@@ -151,9 +151,6 @@
<!-- Label for a printer that is not available. [CHAR LIMIT=25] -->
<string name="printer_unavailable"><xliff:g id="print_job_name" example="Canon-123GHT">%1$s</xliff:g> – unavailable</string>
- <!-- Default message of an alert dialog for app error while generating a print job. [CHAR LIMIT=50] -->
- <string name="print_error_default_message">Couldn\'t generate print job</string>
-
<!-- Arrays -->
<!-- Color mode labels. -->
@@ -200,4 +197,23 @@
holder to start the configuration activities of a print service. Should never be needed
for normal apps.</string>
+ <!-- Error messages -->
+
+ <!-- Message for an error when trying to print to a PDF file. [CHAR LIMIT=50] -->
+ <string name="print_write_error_message">Couldn\'t write to file</string>
+
+ <!-- Default message for an error while generating a print job. [CHAR LIMIT=50] -->
+ <string name="print_error_default_message">Couldn\'t generate print job</string>
+
+ <!-- Label for the retry button in the error message. [CHAR LIMIT=50] -->
+ <string name="print_error_retry">Retry</string>
+
+ <!-- Message for the currently selected printer becoming unavailable. [CHAR LIMIT=50] -->
+ <string name="print_error_printer_unavailable">Printer unavailable</string>
+
+ <!-- Long running operations -->
+
+ <!-- Message for the cancel print operation UI while waiting for cancel to be performed. [CHAR LIMIT=50] -->
+ <string name="print_operation_canceling">Cancelling\u2026</string>
+
</resources>
diff --git a/packages/PrintSpooler/res/values/styles.xml b/packages/PrintSpooler/res/values/styles.xml
index d64380a..9637847 100644
--- a/packages/PrintSpooler/res/values/styles.xml
+++ b/packages/PrintSpooler/res/values/styles.xml
@@ -16,13 +16,6 @@
<resources>
- <style name="PrintOptionTitleTextAppearance">
- <item name="android:textStyle">normal</item>
- <item name="android:textSize">14sp</item>
- <item name="android:textAllCaps">true</item>
- <item name="android:textColor">@color/print_option_title</item>
- </style>
-
<style name="PrintOptionSpinnerStyle">
<item name="android:paddingTop">0dip</item>
<item name="android:paddingBottom">0dip</item>
@@ -30,7 +23,7 @@
</style>
<style name="PrintOptionEditTextStyle">
- <item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
+
<item name="android:singleLine">true</item>
<item name="android:ellipsize">end</item>
</style>
diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml
index 94ab895..40bf725 100644
--- a/packages/PrintSpooler/res/values/themes.xml
+++ b/packages/PrintSpooler/res/values/themes.xml
@@ -16,15 +16,6 @@
<resources>
- <style name="PrintJobConfigActivityTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
- <item name="android:windowBackground">@android:color/transparent</item>
- <item name="android:windowSoftInputMode">stateAlwaysHidden|adjustResize</item>
- <item name="android:windowIsTranslucent">true</item>
- <item name="android:backgroundDimEnabled">true</item>
- <item name="android:colorBackgroundCacheHint">@android:color/transparent</item>
- <item name="android:windowIsFloating">true</item>
- </style>
-
<style name="SelectPrinterActivityTheme" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:actionBarStyle">@style/SelectPrinterActivityActionBarStyle</item>
</style>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java b/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java
deleted file mode 100644
index c1c4d21..0000000
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.printspooler;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.FrameLayout;
-
-public class PrintDialogFrame extends FrameLayout {
-
- public final int mMaxWidth;
-
- public int mHeight;
-
- public PrintDialogFrame(Context context, AttributeSet attrs) {
- super(context, attrs);
- mMaxWidth = context.getResources().getDimensionPixelSize(
- R.dimen.print_dialog_frame_max_width_dip);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- int measuredWidth = getMeasuredWidth();
- final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- switch (widthMode) {
- case MeasureSpec.UNSPECIFIED: {
- measuredWidth = mMaxWidth;
- } break;
-
- case MeasureSpec.AT_MOST: {
- final int receivedWidth = MeasureSpec.getSize(widthMeasureSpec);
- measuredWidth = Math.min(mMaxWidth, receivedWidth);
- } break;
- }
-
- mHeight = Math.max(mHeight, getMeasuredHeight());
-
- int measuredHeight = getMeasuredHeight();
- final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- switch (heightMode) {
- case MeasureSpec.UNSPECIFIED: {
- measuredHeight = mHeight;
- } break;
-
- case MeasureSpec.AT_MOST: {
- final int receivedHeight = MeasureSpec.getSize(heightMeasureSpec);
- measuredHeight = Math.min(mHeight, receivedHeight);
- } break;
- }
-
- setMeasuredDimension(measuredWidth, measuredHeight);
- }
-}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
deleted file mode 100644
index e3d8d05..0000000
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ /dev/null
@@ -1,2966 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.printspooler;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.app.LoaderManager;
-import android.content.ActivityNotFoundException;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.Loader;
-import android.content.ServiceConnection;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.database.DataSetObserver;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.IBinder.DeathRecipient;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.print.ILayoutResultCallback;
-import android.print.IPrintDocumentAdapter;
-import android.print.IPrintDocumentAdapterObserver;
-import android.print.IWriteResultCallback;
-import android.print.PageRange;
-import android.print.PrintAttributes;
-import android.print.PrintAttributes.Margins;
-import android.print.PrintAttributes.MediaSize;
-import android.print.PrintAttributes.Resolution;
-import android.print.PrintDocumentAdapter;
-import android.print.PrintDocumentInfo;
-import android.print.PrintJobId;
-import android.print.PrintJobInfo;
-import android.print.PrintManager;
-import android.print.PrinterCapabilitiesInfo;
-import android.print.PrinterId;
-import android.print.PrinterInfo;
-import android.printservice.PrintService;
-import android.printservice.PrintServiceInfo;
-import android.provider.DocumentsContract;
-import android.text.Editable;
-import android.text.TextUtils;
-import android.text.TextUtils.SimpleStringSplitter;
-import android.text.TextWatcher;
-import android.util.ArrayMap;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.MeasureSpec;
-import android.view.View.OnAttachStateChangeListener;
-import android.view.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.view.ViewPropertyAnimator;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
-import android.widget.BaseAdapter;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.Spinner;
-import android.widget.TextView;
-
-import com.android.printspooler.MediaSizeUtils.MediaSizeComparator;
-
-import libcore.io.IoUtils;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Activity for configuring a print job.
- */
-public class PrintJobConfigActivity extends Activity {
-
- private static final String LOG_TAG = "PrintJobConfigActivity";
-
- private static final boolean DEBUG = false;
-
- public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
-
- private static final int LOADER_ID_PRINTERS_LOADER = 1;
-
- private static final int ORIENTATION_PORTRAIT = 0;
- private static final int ORIENTATION_LANDSCAPE = 1;
-
- private static final int DEST_ADAPTER_MAX_ITEM_COUNT = 9;
-
- private static final int DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF = Integer.MAX_VALUE;
- private static final int DEST_ADAPTER_ITEM_ID_ALL_PRINTERS = Integer.MAX_VALUE - 1;
-
- private static final int ACTIVITY_REQUEST_CREATE_FILE = 1;
- private static final int ACTIVITY_REQUEST_SELECT_PRINTER = 2;
- private static final int ACTIVITY_POPULATE_ADVANCED_PRINT_OPTIONS = 3;
-
- private static final int CONTROLLER_STATE_FINISHED = 1;
- private static final int CONTROLLER_STATE_FAILED = 2;
- private static final int CONTROLLER_STATE_CANCELLED = 3;
- private static final int CONTROLLER_STATE_INITIALIZED = 4;
- private static final int CONTROLLER_STATE_STARTED = 5;
- private static final int CONTROLLER_STATE_LAYOUT_STARTED = 6;
- private static final int CONTROLLER_STATE_LAYOUT_COMPLETED = 7;
- private static final int CONTROLLER_STATE_WRITE_STARTED = 8;
- private static final int CONTROLLER_STATE_WRITE_COMPLETED = 9;
-
- private static final int EDITOR_STATE_INITIALIZED = 1;
- private static final int EDITOR_STATE_CONFIRMED_PRINT = 2;
- private static final int EDITOR_STATE_CANCELLED = 3;
-
- private static final int MIN_COPIES = 1;
- private static final String MIN_COPIES_STRING = String.valueOf(MIN_COPIES);
-
- private static final Pattern PATTERN_DIGITS = Pattern.compile("[\\d]+");
-
- private static final Pattern PATTERN_ESCAPE_SPECIAL_CHARS = Pattern.compile(
- "(?=[]\\[+&|!(){}^\"~*?:\\\\])");
-
- private static final Pattern PATTERN_PAGE_RANGE = Pattern.compile(
- "[\\s]*[0-9]*[\\s]*[\\-]?[\\s]*[0-9]*[\\s]*?(([,])"
- + "[\\s]*[0-9]*[\\s]*[\\-]?[\\s]*[0-9]*[\\s]*|[\\s]*)+");
-
- public static final PageRange[] ALL_PAGES_ARRAY = new PageRange[] {PageRange.ALL_PAGES};
-
- private final PrintAttributes mOldPrintAttributes = new PrintAttributes.Builder().build();
- private final PrintAttributes mCurrPrintAttributes = new PrintAttributes.Builder().build();
-
- private final DeathRecipient mDeathRecipient = new DeathRecipient() {
- @Override
- public void binderDied() {
- finish();
- }
- };
-
- private Editor mEditor;
- private Document mDocument;
- private PrintController mController;
-
- private PrintJobId mPrintJobId;
-
- private IBinder mIPrintDocumentAdapter;
-
- private Dialog mGeneratingPrintJobDialog;
-
- private PrintSpoolerProvider mSpoolerProvider;
-
- private String mCallingPackageName;
-
- @Override
- protected void onCreate(Bundle bundle) {
- super.onCreate(bundle);
-
- setTitle(R.string.print_dialog);
-
- Bundle extras = getIntent().getExtras();
-
- PrintJobInfo printJob = extras.getParcelable(PrintManager.EXTRA_PRINT_JOB);
- if (printJob == null) {
- throw new IllegalArgumentException("printJob cannot be null");
- }
-
- mPrintJobId = printJob.getId();
- mIPrintDocumentAdapter = extras.getBinder(PrintManager.EXTRA_PRINT_DOCUMENT_ADAPTER);
- if (mIPrintDocumentAdapter == null) {
- throw new IllegalArgumentException("PrintDocumentAdapter cannot be null");
- }
-
- try {
- IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter)
- .setObserver(new PrintDocumentAdapterObserver(this));
- } catch (RemoteException re) {
- finish();
- return;
- }
-
- PrintAttributes attributes = printJob.getAttributes();
- if (attributes != null) {
- mCurrPrintAttributes.copyFrom(attributes);
- }
-
- mCallingPackageName = extras.getString(DocumentsContract.EXTRA_PACKAGE_NAME);
-
- setContentView(R.layout.print_job_config_activity_container);
-
- try {
- mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0);
- } catch (RemoteException re) {
- finish();
- return;
- }
-
- mDocument = new Document();
- mEditor = new Editor();
-
- mSpoolerProvider = new PrintSpoolerProvider(this,
- new Runnable() {
- @Override
- public void run() {
- // We got the spooler so unleash the UI.
- mController = new PrintController(new RemotePrintDocumentAdapter(
- IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
- mSpoolerProvider.getSpooler().generateFileForPrintJob(mPrintJobId)));
- mController.initialize();
-
- mEditor.initialize();
- mEditor.postCreate();
- }
- });
- }
-
- @Override
- public void onResume() {
- super.onResume();
- if (mSpoolerProvider.getSpooler() != null) {
- mEditor.refreshCurrentPrinter();
- }
- }
-
- @Override
- public void onPause() {
- if (isFinishing()) {
- if (mController != null && mController.hasStarted()) {
- mController.finish();
- }
- if (mEditor != null && mEditor.isPrintConfirmed()
- && mController != null && mController.isFinished()) {
- mSpoolerProvider.getSpooler().setPrintJobState(mPrintJobId,
- PrintJobInfo.STATE_QUEUED, null);
- } else {
- mSpoolerProvider.getSpooler().setPrintJobState(mPrintJobId,
- PrintJobInfo.STATE_CANCELED, null);
- }
- if (mGeneratingPrintJobDialog != null) {
- mGeneratingPrintJobDialog.dismiss();
- mGeneratingPrintJobDialog = null;
- }
- mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0);
- mSpoolerProvider.destroy();
- }
- super.onPause();
- }
-
- public boolean onTouchEvent(MotionEvent event) {
- if (mController != null && mEditor != null &&
- !mEditor.isPrintConfirmed() && mEditor.shouldCloseOnTouch(event)) {
- if (!mController.isWorking()) {
- PrintJobConfigActivity.this.finish();
- }
- mEditor.cancel();
- return true;
- }
- return super.onTouchEvent(event);
- }
-
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- event.startTracking();
- }
- return super.onKeyDown(keyCode, event);
- }
-
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (mController != null && mEditor != null) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- if (mEditor.isShwoingGeneratingPrintJobUi()) {
- return true;
- }
- if (event.isTracking() && !event.isCanceled()) {
- if (!mController.isWorking()) {
- PrintJobConfigActivity.this.finish();
- }
- }
- mEditor.cancel();
- return true;
- }
- }
- return super.onKeyUp(keyCode, event);
- }
-
- private boolean printAttributesChanged() {
- return !mOldPrintAttributes.equals(mCurrPrintAttributes);
- }
-
- private class PrintController {
- private final AtomicInteger mRequestCounter = new AtomicInteger();
-
- private final RemotePrintDocumentAdapter mRemotePrintAdapter;
-
- private final Bundle mMetadata;
-
- private final ControllerHandler mHandler;
-
- private final LayoutResultCallback mLayoutResultCallback;
-
- private final WriteResultCallback mWriteResultCallback;
-
- private int mControllerState = CONTROLLER_STATE_INITIALIZED;
-
- private boolean mHasStarted;
-
- private PageRange[] mRequestedPages;
-
- public PrintController(RemotePrintDocumentAdapter adapter) {
- mRemotePrintAdapter = adapter;
- mMetadata = new Bundle();
- mHandler = new ControllerHandler(getMainLooper());
- mLayoutResultCallback = new LayoutResultCallback(mHandler);
- mWriteResultCallback = new WriteResultCallback(mHandler);
- }
-
- public void initialize() {
- mHasStarted = false;
- mControllerState = CONTROLLER_STATE_INITIALIZED;
- }
-
- public void cancel() {
- if (isWorking()) {
- mRemotePrintAdapter.cancel();
- }
- mControllerState = CONTROLLER_STATE_CANCELLED;
- }
-
- public boolean isCancelled() {
- return (mControllerState == CONTROLLER_STATE_CANCELLED);
- }
-
- public boolean isFinished() {
- return (mControllerState == CONTROLLER_STATE_FINISHED);
- }
-
- public boolean hasStarted() {
- return mHasStarted;
- }
-
- public boolean hasPerformedLayout() {
- return mControllerState >= CONTROLLER_STATE_LAYOUT_COMPLETED;
- }
-
- public boolean isPerformingLayout() {
- return mControllerState == CONTROLLER_STATE_LAYOUT_STARTED;
- }
-
- public boolean isWorking() {
- return mControllerState == CONTROLLER_STATE_LAYOUT_STARTED
- || mControllerState == CONTROLLER_STATE_WRITE_STARTED;
- }
-
- public void start() {
- mControllerState = CONTROLLER_STATE_STARTED;
- mHasStarted = true;
- mRemotePrintAdapter.start();
- }
-
- public void update() {
- if (!mController.hasStarted()) {
- mController.start();
- }
-
- // If the print attributes are the same and we are performing
- // a layout, then we have to wait for it to completed which will
- // trigger writing of the necessary pages.
- final boolean printAttributesChanged = printAttributesChanged();
- if (!printAttributesChanged && isPerformingLayout()) {
- return;
- }
-
- // If print is confirmed we always do a layout since the previous
- // ones were for preview and this one is for printing.
- if (!printAttributesChanged && !mEditor.isPrintConfirmed()) {
- if (mDocument.info == null) {
- // We are waiting for the result of a layout, so do nothing.
- return;
- }
- // If the attributes didn't change and we have done a layout, then
- // we do not do a layout but may have to ask the app to write some
- // pages. Hence, pretend layout completed and nothing changed, so
- // we handle writing as usual.
- handleOnLayoutFinished(mDocument.info, false, mRequestCounter.get());
- } else {
- mSpoolerProvider.getSpooler().setPrintJobAttributesNoPersistence(
- mPrintJobId, mCurrPrintAttributes);
-
- mMetadata.putBoolean(PrintDocumentAdapter.EXTRA_PRINT_PREVIEW,
- !mEditor.isPrintConfirmed());
-
- mControllerState = CONTROLLER_STATE_LAYOUT_STARTED;
-
- mRemotePrintAdapter.layout(mOldPrintAttributes, mCurrPrintAttributes,
- mLayoutResultCallback, mMetadata, mRequestCounter.incrementAndGet());
-
- mOldPrintAttributes.copyFrom(mCurrPrintAttributes);
- }
- }
-
- public void finish() {
- mControllerState = CONTROLLER_STATE_FINISHED;
- mRemotePrintAdapter.finish();
- }
-
- private void handleOnLayoutFinished(PrintDocumentInfo info,
- boolean layoutChanged, int sequence) {
- if (mRequestCounter.get() != sequence) {
- return;
- }
-
- if (isCancelled()) {
- mEditor.updateUi();
- if (mEditor.isDone()) {
- PrintJobConfigActivity.this.finish();
- }
- return;
- }
-
- final int oldControllerState = mControllerState;
-
- if (mControllerState == CONTROLLER_STATE_LAYOUT_STARTED) {
- mControllerState = CONTROLLER_STATE_LAYOUT_COMPLETED;
- }
-
- // For layout purposes we care only whether the type or the page
- // count changed. We still do not have the size since we did not
- // call write. We use "layoutChanged" set by the application to
- // know whether something else changed about the document.
- final boolean infoChanged = !equalsIgnoreSize(info, mDocument.info);
- // If the info changed, we update the document and the print job.
- if (infoChanged) {
- mDocument.info = info;
- // Set the info.
- mSpoolerProvider.getSpooler().setPrintJobPrintDocumentInfoNoPersistence(
- mPrintJobId, info);
- }
-
- // If the document info or the layout changed, then
- // drop the pages since we have to fetch them again.
- if (infoChanged || layoutChanged) {
- mDocument.pages = null;
- mSpoolerProvider.getSpooler().setPrintJobPagesNoPersistence(
- mPrintJobId, null);
- }
-
- PageRange[] oldRequestedPages = mRequestedPages;
-
- // No pages means that the user selected an invalid range while we
- // were doing a layout or the layout returned a document info for
- // which the selected range is invalid. In such a case we do not
- // write anything and wait for the user to fix the range which will
- // trigger an update.
- mRequestedPages = mEditor.getRequestedPages();
- if (mRequestedPages == null || mRequestedPages.length == 0) {
- mEditor.updateUi();
- if (mEditor.isDone()) {
- PrintJobConfigActivity.this.finish();
- }
- return;
- } else {
- // If print is not confirmed we just ask for the first of the
- // selected pages to emulate a behavior that shows preview
- // increasing the chances that apps will implement the APIs
- // correctly.
- if (!mEditor.isPrintConfirmed()) {
- if (ALL_PAGES_ARRAY.equals(mRequestedPages)) {
- mRequestedPages = new PageRange[] {new PageRange(0, 0)};
- } else {
- final int firstPage = mRequestedPages[0].getStart();
- mRequestedPages = new PageRange[] {new PageRange(firstPage, firstPage)};
- }
- }
- }
-
- // If the info and the layout did not change...
- if (!infoChanged && !layoutChanged
- // and we have the requested pages ...
- && (PageRangeUtils.contains(mDocument.pages, mRequestedPages))
- // ...or the requested pages are being written...
- || (oldControllerState == CONTROLLER_STATE_WRITE_STARTED
- && oldRequestedPages != null
- && PageRangeUtils.contains(oldRequestedPages, mRequestedPages))) {
- // Nothing interesting changed and we have all requested pages.
- // Then update the print jobs's pages as we will not do a write
- // and we usually update the pages in the write complete callback.
- if (mDocument.pages != null) {
- // Update the print job's pages given we have them.
- updatePrintJobPages(mDocument.pages, mRequestedPages);
- }
- mEditor.updateUi();
- if (mEditor.isDone()) {
- requestCreatePdfFileOrFinish();
- }
- return;
- }
-
- mEditor.updateUi();
-
- // Request a write of the pages of interest.
- mControllerState = CONTROLLER_STATE_WRITE_STARTED;
- mRemotePrintAdapter.write(mRequestedPages, mWriteResultCallback,
- mRequestCounter.incrementAndGet());
- }
-
- private void handleOnLayoutFailed(final CharSequence error, int sequence) {
- if (mRequestCounter.get() != sequence) {
- return;
- }
- mControllerState = CONTROLLER_STATE_FAILED;
- mEditor.showUi(Editor.UI_ERROR, new Runnable() {
- @Override
- public void run() {
- if (!TextUtils.isEmpty(error)) {
- TextView messageView = (TextView) findViewById(R.id.message);
- messageView.setText(error);
- }
- }
- });
- }
-
- private void handleOnWriteFinished(PageRange[] pages, int sequence) {
- if (mRequestCounter.get() != sequence) {
- return;
- }
-
- if (isCancelled()) {
- if (mEditor.isDone()) {
- PrintJobConfigActivity.this.finish();
- }
- return;
- }
-
- mControllerState = CONTROLLER_STATE_WRITE_COMPLETED;
-
- // Update the document size.
- File file = mSpoolerProvider.getSpooler()
- .generateFileForPrintJob(mPrintJobId);
- mDocument.info.setDataSize(file.length());
-
- // Update the print job with the updated info.
- mSpoolerProvider.getSpooler().setPrintJobPrintDocumentInfoNoPersistence(
- mPrintJobId, mDocument.info);
-
- // Update which pages we have fetched.
- mDocument.pages = PageRangeUtils.normalize(pages);
-
- if (DEBUG) {
- Log.i(LOG_TAG, "Requested: " + Arrays.toString(mRequestedPages)
- + " and got: " + Arrays.toString(mDocument.pages));
- }
-
- updatePrintJobPages(mDocument.pages, mRequestedPages);
-
- if (mEditor.isDone()) {
- requestCreatePdfFileOrFinish();
- }
- }
-
- private void updatePrintJobPages(PageRange[] writtenPages, PageRange[] requestedPages) {
- // Adjust the print job pages based on what was requested and written.
- // The cases are ordered in the most expected to the least expected.
- if (Arrays.equals(writtenPages, requestedPages)) {
- // We got a document with exactly the pages we wanted. Hence,
- // the printer has to print all pages in the data.
- mSpoolerProvider.getSpooler().setPrintJobPagesNoPersistence(mPrintJobId,
- ALL_PAGES_ARRAY);
- } else if (Arrays.equals(writtenPages, ALL_PAGES_ARRAY)) {
- // We requested specific pages but got all of them. Hence,
- // the printer has to print only the requested pages.
- mSpoolerProvider.getSpooler().setPrintJobPagesNoPersistence(mPrintJobId,
- requestedPages);
- } else if (PageRangeUtils.contains(writtenPages, requestedPages)) {
- // We requested specific pages and got more but not all pages.
- // Hence, we have to offset appropriately the printed pages to
- // be based off the start of the written ones instead of zero.
- // The written pages are always non-null and not empty.
- final int offset = -writtenPages[0].getStart();
- PageRange[] offsetPages = Arrays.copyOf(requestedPages, requestedPages.length);
- PageRangeUtils.offset(offsetPages, offset);
- mSpoolerProvider.getSpooler().setPrintJobPagesNoPersistence(mPrintJobId,
- offsetPages);
- } else if (Arrays.equals(requestedPages, ALL_PAGES_ARRAY)
- && writtenPages.length == 1 && writtenPages[0].getStart() == 0
- && writtenPages[0].getEnd() == mDocument.info.getPageCount() - 1) {
- // We requested all pages via the special constant and got all
- // of them as an explicit enumeration. Hence, the printer has
- // to print only the requested pages.
- mSpoolerProvider.getSpooler().setPrintJobPagesNoPersistence(mPrintJobId,
- writtenPages);
- } else {
- // We did not get the pages we requested, then the application
- // misbehaves, so we fail quickly.
- mControllerState = CONTROLLER_STATE_FAILED;
- Log.e(LOG_TAG, "Received invalid pages from the app: requested="
- + Arrays.toString(requestedPages) + " written="
- + Arrays.toString(writtenPages));
- mEditor.showUi(Editor.UI_ERROR, null);
- }
- }
-
- private void requestCreatePdfFileOrFinish() {
- if (mEditor.isPrintingToPdf()) {
- Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
- intent.setType("application/pdf");
- intent.putExtra(Intent.EXTRA_TITLE, mDocument.info.getName());
- intent.putExtra(DocumentsContract.EXTRA_PACKAGE_NAME, mCallingPackageName);
- startActivityForResult(intent, ACTIVITY_REQUEST_CREATE_FILE);
- } else {
- PrintJobConfigActivity.this.finish();
- }
- }
-
- private void handleOnWriteFailed(final CharSequence error, int sequence) {
- if (mRequestCounter.get() != sequence) {
- return;
- }
- mControllerState = CONTROLLER_STATE_FAILED;
- mEditor.showUi(Editor.UI_ERROR, new Runnable() {
- @Override
- public void run() {
- if (!TextUtils.isEmpty(error)) {
- TextView messageView = (TextView) findViewById(R.id.message);
- messageView.setText(error);
- }
- }
- });
- }
-
- private boolean equalsIgnoreSize(PrintDocumentInfo lhs, PrintDocumentInfo rhs) {
- if (lhs == rhs) {
- return true;
- }
- if (lhs == null) {
- if (rhs != null) {
- return false;
- }
- } else {
- if (rhs == null) {
- return false;
- }
- if (lhs.getContentType() != rhs.getContentType()
- || lhs.getPageCount() != rhs.getPageCount()) {
- return false;
- }
- }
- return true;
- }
-
- private final class ControllerHandler extends Handler {
- public static final int MSG_ON_LAYOUT_FINISHED = 1;
- public static final int MSG_ON_LAYOUT_FAILED = 2;
- public static final int MSG_ON_WRITE_FINISHED = 3;
- public static final int MSG_ON_WRITE_FAILED = 4;
-
- public ControllerHandler(Looper looper) {
- super(looper, null, false);
- }
-
- @Override
- public void handleMessage(Message message) {
- switch (message.what) {
- case MSG_ON_LAYOUT_FINISHED: {
- PrintDocumentInfo info = (PrintDocumentInfo) message.obj;
- final boolean changed = (message.arg1 == 1);
- final int sequence = message.arg2;
- handleOnLayoutFinished(info, changed, sequence);
- } break;
-
- case MSG_ON_LAYOUT_FAILED: {
- CharSequence error = (CharSequence) message.obj;
- final int sequence = message.arg1;
- handleOnLayoutFailed(error, sequence);
- } break;
-
- case MSG_ON_WRITE_FINISHED: {
- PageRange[] pages = (PageRange[]) message.obj;
- final int sequence = message.arg1;
- handleOnWriteFinished(pages, sequence);
- } break;
-
- case MSG_ON_WRITE_FAILED: {
- CharSequence error = (CharSequence) message.obj;
- final int sequence = message.arg1;
- handleOnWriteFailed(error, sequence);
- } break;
- }
- }
- }
- }
-
- private static final class LayoutResultCallback extends ILayoutResultCallback.Stub {
- private final WeakReference<PrintController.ControllerHandler> mWeakHandler;
-
- public LayoutResultCallback(PrintController.ControllerHandler handler) {
- mWeakHandler = new WeakReference<PrintController.ControllerHandler>(handler);
- }
-
- @Override
- public void onLayoutFinished(PrintDocumentInfo info, boolean changed, int sequence) {
- Handler handler = mWeakHandler.get();
- if (handler != null) {
- handler.obtainMessage(PrintController.ControllerHandler.MSG_ON_LAYOUT_FINISHED,
- changed ? 1 : 0, sequence, info).sendToTarget();
- }
- }
-
- @Override
- public void onLayoutFailed(CharSequence error, int sequence) {
- Handler handler = mWeakHandler.get();
- if (handler != null) {
- handler.obtainMessage(PrintController.ControllerHandler.MSG_ON_LAYOUT_FAILED,
- sequence, 0, error).sendToTarget();
- }
- }
- }
-
- private static final class WriteResultCallback extends IWriteResultCallback.Stub {
- private final WeakReference<PrintController.ControllerHandler> mWeakHandler;
-
- public WriteResultCallback(PrintController.ControllerHandler handler) {
- mWeakHandler = new WeakReference<PrintController.ControllerHandler>(handler);
- }
-
- @Override
- public void onWriteFinished(PageRange[] pages, int sequence) {
- Handler handler = mWeakHandler.get();
- if (handler != null) {
- handler.obtainMessage(PrintController.ControllerHandler.MSG_ON_WRITE_FINISHED,
- sequence, 0, pages).sendToTarget();
- }
- }
-
- @Override
- public void onWriteFailed(CharSequence error, int sequence) {
- Handler handler = mWeakHandler.get();
- if (handler != null) {
- handler.obtainMessage(PrintController.ControllerHandler.MSG_ON_WRITE_FAILED,
- sequence, 0, error).sendToTarget();
- }
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case ACTIVITY_REQUEST_CREATE_FILE: {
- if (data != null) {
- Uri uri = data.getData();
- writePrintJobDataAndFinish(uri);
- } else {
- mEditor.showUi(Editor.UI_EDITING_PRINT_JOB,
- new Runnable() {
- @Override
- public void run() {
- mEditor.initialize();
- mEditor.bindUi();
- mEditor.reselectCurrentPrinter();
- mEditor.updateUi();
- }
- });
- }
- } break;
-
- case ACTIVITY_REQUEST_SELECT_PRINTER: {
- if (resultCode == RESULT_OK) {
- PrinterId printerId = (PrinterId) data.getParcelableExtra(
- INTENT_EXTRA_PRINTER_ID);
- if (printerId != null) {
- mEditor.ensurePrinterSelected(printerId);
- break;
- }
- }
- mEditor.ensureCurrentPrinterSelected();
- } break;
-
- case ACTIVITY_POPULATE_ADVANCED_PRINT_OPTIONS: {
- if (resultCode == RESULT_OK) {
- PrintJobInfo printJobInfo = (PrintJobInfo) data.getParcelableExtra(
- PrintService.EXTRA_PRINT_JOB_INFO);
- if (printJobInfo != null) {
- mEditor.updateFromAdvancedOptions(printJobInfo);
- break;
- }
- }
- mEditor.cancel();
- PrintJobConfigActivity.this.finish();
- } break;
- }
- }
-
- private void writePrintJobDataAndFinish(final Uri uri) {
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- InputStream in = null;
- OutputStream out = null;
- try {
- PrintJobInfo printJob = mSpoolerProvider.getSpooler()
- .getPrintJobInfo(mPrintJobId, PrintManager.APP_ID_ANY);
- if (printJob == null) {
- return null;
- }
- File file = mSpoolerProvider.getSpooler()
- .generateFileForPrintJob(mPrintJobId);
- in = new FileInputStream(file);
- out = getContentResolver().openOutputStream(uri);
- final byte[] buffer = new byte[8192];
- while (true) {
- final int readByteCount = in.read(buffer);
- if (readByteCount < 0) {
- break;
- }
- out.write(buffer, 0, readByteCount);
- }
- } catch (FileNotFoundException fnfe) {
- Log.e(LOG_TAG, "Error writing print job data!", fnfe);
- } catch (IOException ioe) {
- Log.e(LOG_TAG, "Error writing print job data!", ioe);
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
- }
- return null;
- }
-
- @Override
- public void onPostExecute(Void result) {
- mEditor.cancel();
- PrintJobConfigActivity.this.finish();
- }
- }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
- }
-
- private final class Editor {
- private static final int UI_NONE = 0;
- private static final int UI_EDITING_PRINT_JOB = 1;
- private static final int UI_GENERATING_PRINT_JOB = 2;
- private static final int UI_ERROR = 3;
-
- private EditText mCopiesEditText;
-
- private TextView mRangeOptionsTitle;
- private TextView mPageRangeTitle;
- private EditText mPageRangeEditText;
-
- private Spinner mDestinationSpinner;
- private DestinationAdapter mDestinationSpinnerAdapter;
-
- private Spinner mMediaSizeSpinner;
- private ArrayAdapter<SpinnerItem<MediaSize>> mMediaSizeSpinnerAdapter;
-
- private Spinner mColorModeSpinner;
- private ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter;
-
- private Spinner mOrientationSpinner;
- private ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter;
-
- private Spinner mRangeOptionsSpinner;
- private ArrayAdapter<SpinnerItem<Integer>> mRangeOptionsSpinnerAdapter;
-
- private SimpleStringSplitter mStringCommaSplitter =
- new SimpleStringSplitter(',');
-
- private View mContentContainer;
-
- private View mAdvancedPrintOptionsContainer;
-
- private Button mAdvancedOptionsButton;
-
- private Button mPrintButton;
-
- private PrinterId mNextPrinterId;
-
- private PrinterInfo mCurrentPrinter;
-
- private MediaSizeComparator mMediaSizeComparator;
-
- private final OnFocusChangeListener mFocusListener = new OnFocusChangeListener() {
- @Override
- public void onFocusChange(View view, boolean hasFocus) {
- EditText editText = (EditText) view;
- if (!TextUtils.isEmpty(editText.getText())) {
- editText.setSelection(editText.getText().length());
- }
- }
- };
-
- private final OnItemSelectedListener mOnItemSelectedListener =
- new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> spinner, View view, int position, long id) {
- if (spinner == mDestinationSpinner) {
- if (mIgnoreNextDestinationChange) {
- mIgnoreNextDestinationChange = false;
- return;
- }
-
- if (position == AdapterView.INVALID_POSITION) {
- updateUi();
- return;
- }
-
- if (id == DEST_ADAPTER_ITEM_ID_ALL_PRINTERS) {
- startSelectPrinterActivity();
- return;
- }
-
- mCapabilitiesTimeout.remove();
-
- mCurrentPrinter = (PrinterInfo) mDestinationSpinnerAdapter
- .getItem(position);
-
- mSpoolerProvider.getSpooler().setPrintJobPrinterNoPersistence(
- mPrintJobId, mCurrentPrinter);
-
- if (mCurrentPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE) {
- mCapabilitiesTimeout.post();
- updateUi();
- return;
- }
-
- PrinterCapabilitiesInfo capabilities = mCurrentPrinter.getCapabilities();
- if (capabilities == null) {
- mCapabilitiesTimeout.post();
- updateUi();
- refreshCurrentPrinter();
- } else {
- updatePrintAttributes(capabilities);
- updateUi();
- mController.update();
- refreshCurrentPrinter();
- }
- } else if (spinner == mMediaSizeSpinner) {
- if (mIgnoreNextMediaSizeChange) {
- mIgnoreNextMediaSizeChange = false;
- return;
- }
- if (mOldMediaSizeSelectionIndex
- == mMediaSizeSpinner.getSelectedItemPosition()) {
- mOldMediaSizeSelectionIndex = AdapterView.INVALID_POSITION;
- return;
- }
- SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position);
- if (mOrientationSpinner.getSelectedItemPosition() == 0) {
- mCurrPrintAttributes.setMediaSize(mediaItem.value.asPortrait());
- } else {
- mCurrPrintAttributes.setMediaSize(mediaItem.value.asLandscape());
- }
- if (!hasErrors()) {
- mController.update();
- }
- } else if (spinner == mColorModeSpinner) {
- if (mIgnoreNextColorChange) {
- mIgnoreNextColorChange = false;
- return;
- }
- if (mOldColorModeSelectionIndex
- == mColorModeSpinner.getSelectedItemPosition()) {
- mOldColorModeSelectionIndex = AdapterView.INVALID_POSITION;
- return;
- }
- SpinnerItem<Integer> colorModeItem =
- mColorModeSpinnerAdapter.getItem(position);
- mCurrPrintAttributes.setColorMode(colorModeItem.value);
- if (!hasErrors()) {
- mController.update();
- }
- } else if (spinner == mOrientationSpinner) {
- if (mIgnoreNextOrientationChange) {
- mIgnoreNextOrientationChange = false;
- return;
- }
- SpinnerItem<Integer> orientationItem =
- mOrientationSpinnerAdapter.getItem(position);
- setCurrentPrintAttributesOrientation(orientationItem.value);
- if (!hasErrors()) {
- mController.update();
- }
- } else if (spinner == mRangeOptionsSpinner) {
- if (mIgnoreNextRangeOptionChange) {
- mIgnoreNextRangeOptionChange = false;
- return;
- }
- updateUi();
- if (!hasErrors()) {
- mController.update();
- }
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- /* do nothing*/
- }
- };
-
- private void setCurrentPrintAttributesOrientation(int orientation) {
- MediaSize mediaSize = mCurrPrintAttributes.getMediaSize();
- if (orientation == ORIENTATION_PORTRAIT) {
- if (!mediaSize.isPortrait()) {
- // Rotate the media size.
- mCurrPrintAttributes.setMediaSize(mediaSize.asPortrait());
-
- // Rotate the resolution.
- Resolution oldResolution = mCurrPrintAttributes.getResolution();
- Resolution newResolution = new Resolution(
- oldResolution.getId(),
- oldResolution.getLabel(),
- oldResolution.getVerticalDpi(),
- oldResolution.getHorizontalDpi());
- mCurrPrintAttributes.setResolution(newResolution);
-
- // Rotate the physical margins.
- Margins oldMinMargins = mCurrPrintAttributes.getMinMargins();
- Margins newMinMargins = new Margins(
- oldMinMargins.getBottomMils(),
- oldMinMargins.getLeftMils(),
- oldMinMargins.getTopMils(),
- oldMinMargins.getRightMils());
- mCurrPrintAttributes.setMinMargins(newMinMargins);
- }
- } else {
- if (mediaSize.isPortrait()) {
- // Rotate the media size.
- mCurrPrintAttributes.setMediaSize(mediaSize.asLandscape());
-
- // Rotate the resolution.
- Resolution oldResolution = mCurrPrintAttributes.getResolution();
- Resolution newResolution = new Resolution(
- oldResolution.getId(),
- oldResolution.getLabel(),
- oldResolution.getVerticalDpi(),
- oldResolution.getHorizontalDpi());
- mCurrPrintAttributes.setResolution(newResolution);
-
- // Rotate the physical margins.
- Margins oldMinMargins = mCurrPrintAttributes.getMinMargins();
- Margins newMargins = new Margins(
- oldMinMargins.getTopMils(),
- oldMinMargins.getRightMils(),
- oldMinMargins.getBottomMils(),
- oldMinMargins.getLeftMils());
- mCurrPrintAttributes.setMinMargins(newMargins);
- }
- }
- }
-
- private void updatePrintAttributes(PrinterCapabilitiesInfo capabilities) {
- PrintAttributes defaults = capabilities.getDefaults();
-
- // Sort the media sizes based on the current locale.
- List<MediaSize> sortedMediaSizes = new ArrayList<MediaSize>(
- capabilities.getMediaSizes());
- Collections.sort(sortedMediaSizes, mMediaSizeComparator);
-
- // Media size.
- MediaSize currMediaSize = mCurrPrintAttributes.getMediaSize();
- if (currMediaSize == null) {
- mCurrPrintAttributes.setMediaSize(defaults.getMediaSize());
- } else {
- MediaSize currMediaSizePortrait = currMediaSize.asPortrait();
- final int mediaSizeCount = sortedMediaSizes.size();
- for (int i = 0; i < mediaSizeCount; i++) {
- MediaSize mediaSize = sortedMediaSizes.get(i);
- if (currMediaSizePortrait.equals(mediaSize.asPortrait())) {
- mCurrPrintAttributes.setMediaSize(currMediaSize);
- break;
- }
- }
- }
-
- // Color mode.
- final int colorMode = mCurrPrintAttributes.getColorMode();
- if ((capabilities.getColorModes() & colorMode) == 0) {
- mCurrPrintAttributes.setColorMode(colorMode);
- }
-
- // Resolution
- Resolution resolution = mCurrPrintAttributes.getResolution();
- if (resolution == null || !capabilities.getResolutions().contains(resolution)) {
- mCurrPrintAttributes.setResolution(defaults.getResolution());
- }
-
- // Margins.
- Margins margins = mCurrPrintAttributes.getMinMargins();
- if (margins == null) {
- mCurrPrintAttributes.setMinMargins(defaults.getMinMargins());
- } else {
- Margins minMargins = capabilities.getMinMargins();
- if (margins.getLeftMils() < minMargins.getLeftMils()
- || margins.getTopMils() < minMargins.getTopMils()
- || margins.getRightMils() > minMargins.getRightMils()
- || margins.getBottomMils() > minMargins.getBottomMils()) {
- mCurrPrintAttributes.setMinMargins(defaults.getMinMargins());
- }
- }
- }
-
- private final TextWatcher mCopiesTextWatcher = new TextWatcher() {
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- /* do nothing */
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- /* do nothing */
- }
-
- @Override
- public void afterTextChanged(Editable editable) {
- if (mIgnoreNextCopiesChange) {
- mIgnoreNextCopiesChange = false;
- return;
- }
-
- final boolean hadErrors = hasErrors();
-
- if (editable.length() == 0) {
- mCopiesEditText.setError("");
- updateUi();
- return;
- }
-
- int copies = 0;
- try {
- copies = Integer.parseInt(editable.toString());
- } catch (NumberFormatException nfe) {
- /* ignore */
- }
-
- if (copies < MIN_COPIES) {
- mCopiesEditText.setError("");
- updateUi();
- return;
- }
-
- mCopiesEditText.setError(null);
- mSpoolerProvider.getSpooler().setPrintJobCopiesNoPersistence(
- mPrintJobId, copies);
- updateUi();
-
- if (hadErrors && !hasErrors() && printAttributesChanged()) {
- mController.update();
- }
- }
- };
-
- private final TextWatcher mRangeTextWatcher = new TextWatcher() {
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- /* do nothing */
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- /* do nothing */
- }
-
- @Override
- public void afterTextChanged(Editable editable) {
- if (mIgnoreNextRangeChange) {
- mIgnoreNextRangeChange = false;
- return;
- }
-
- final boolean hadErrors = hasErrors();
-
- String text = editable.toString();
-
- if (TextUtils.isEmpty(text)) {
- mPageRangeEditText.setError("");
- updateUi();
- return;
- }
-
- String escapedText = PATTERN_ESCAPE_SPECIAL_CHARS.matcher(text).replaceAll("////");
- if (!PATTERN_PAGE_RANGE.matcher(escapedText).matches()) {
- mPageRangeEditText.setError("");
- updateUi();
- return;
- }
-
- // The range
- Matcher matcher = PATTERN_DIGITS.matcher(text);
- while (matcher.find()) {
- String numericString = text.substring(matcher.start(), matcher.end()).trim();
- if (TextUtils.isEmpty(numericString)) {
- continue;
- }
- final int pageIndex = Integer.parseInt(numericString);
- if (pageIndex < 1 || pageIndex > mDocument.info.getPageCount()) {
- mPageRangeEditText.setError("");
- updateUi();
- return;
- }
- }
-
- // We intentionally do not catch the case of the from page being
- // greater than the to page. When computing the requested pages
- // we just swap them if necessary.
-
- // Keep the print job up to date with the selected pages if we
- // know how many pages are there in the document.
- PageRange[] requestedPages = getRequestedPages();
- if (requestedPages != null && requestedPages.length > 0
- && requestedPages[requestedPages.length - 1].getEnd()
- < mDocument.info.getPageCount()) {
- mSpoolerProvider.getSpooler().setPrintJobPagesNoPersistence(
- mPrintJobId, requestedPages);
- }
-
- mPageRangeEditText.setError(null);
- mPrintButton.setEnabled(true);
- updateUi();
-
- if (hadErrors && !hasErrors() && printAttributesChanged()) {
- updateUi();
- }
- }
- };
-
- private final WaitForPrinterCapabilitiesTimeout mCapabilitiesTimeout =
- new WaitForPrinterCapabilitiesTimeout();
-
- private int mEditorState;
-
- private boolean mIgnoreNextDestinationChange;
- private int mOldMediaSizeSelectionIndex;
- private int mOldColorModeSelectionIndex;
- private boolean mIgnoreNextOrientationChange;
- private boolean mIgnoreNextRangeOptionChange;
- private boolean mIgnoreNextCopiesChange;
- private boolean mIgnoreNextRangeChange;
- private boolean mIgnoreNextMediaSizeChange;
- private boolean mIgnoreNextColorChange;
-
- private int mCurrentUi = UI_NONE;
-
- private boolean mFavoritePrinterSelected;
-
- public Editor() {
- showUi(UI_EDITING_PRINT_JOB, null);
- }
-
- public void postCreate() {
- // Destination.
- mMediaSizeComparator = new MediaSizeComparator(PrintJobConfigActivity.this);
- mDestinationSpinnerAdapter = new DestinationAdapter();
- mDestinationSpinnerAdapter.registerDataSetObserver(new DataSetObserver() {
- @Override
- public void onChanged() {
- // Initially, we have only safe to PDF as a printer but after some
- // printers are loaded we want to select the user's favorite one
- // which is the first.
- if (!mFavoritePrinterSelected && mDestinationSpinnerAdapter.getCount() > 1) {
- mFavoritePrinterSelected = true;
- mDestinationSpinner.setSelection(0);
- // Workaround again the weird spinner behavior to notify for selection
- // change on the next layout pass as the current printer is used below.
- mCurrentPrinter = (PrinterInfo) mDestinationSpinnerAdapter.getItem(0);
- }
-
- // If there is a next printer to select and we succeed selecting
- // it - done. Let the selection handling code make everything right.
- if (mNextPrinterId != null && selectPrinter(mNextPrinterId)) {
- mNextPrinterId = null;
- return;
- }
-
- // If the current printer properties changed, we update the UI.
- if (mCurrentPrinter != null) {
- final int printerCount = mDestinationSpinnerAdapter.getCount();
- for (int i = 0; i < printerCount; i++) {
- Object item = mDestinationSpinnerAdapter.getItem(i);
- // Some items are not printers
- if (item instanceof PrinterInfo) {
- PrinterInfo printer = (PrinterInfo) item;
- if (!printer.getId().equals(mCurrentPrinter.getId())) {
- continue;
- }
-
- // If nothing changed - done.
- if (mCurrentPrinter.equals(printer)) {
- return;
- }
-
- // If the current printer became available and has no
- // capabilities, we refresh it.
- if (mCurrentPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE
- && printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE
- && printer.getCapabilities() == null) {
- if (!mCapabilitiesTimeout.isPosted()) {
- mCapabilitiesTimeout.post();
- }
- mCurrentPrinter.copyFrom(printer);
- refreshCurrentPrinter();
- return;
- }
-
- // If the current printer became unavailable or its
- // capabilities go away, we update the UI and add a
- // timeout to declare the printer as unavailable.
- if ((mCurrentPrinter.getStatus() != PrinterInfo.STATUS_UNAVAILABLE
- && printer.getStatus() == PrinterInfo.STATUS_UNAVAILABLE)
- || (mCurrentPrinter.getCapabilities() != null
- && printer.getCapabilities() == null)) {
- if (!mCapabilitiesTimeout.isPosted()) {
- mCapabilitiesTimeout.post();
- }
- mCurrentPrinter.copyFrom(printer);
- updateUi();
- return;
- }
-
- // We just refreshed the current printer.
- if (printer.getCapabilities() != null
- && mCapabilitiesTimeout.isPosted()) {
- mCapabilitiesTimeout.remove();
- updatePrintAttributes(printer.getCapabilities());
- updateUi();
- mController.update();
- }
-
- // Update the UI if capabilities changed.
- boolean capabilitiesChanged = false;
-
- if (mCurrentPrinter.getCapabilities() == null) {
- if (printer.getCapabilities() != null) {
- updatePrintAttributes(printer.getCapabilities());
- capabilitiesChanged = true;
- }
- } else if (!mCurrentPrinter.getCapabilities().equals(
- printer.getCapabilities())) {
- capabilitiesChanged = true;
- }
-
- // Update the UI if the status changed.
- final boolean statusChanged = mCurrentPrinter.getStatus()
- != printer.getStatus();
-
- // Update the printer with the latest info.
- if (!mCurrentPrinter.equals(printer)) {
- mCurrentPrinter.copyFrom(printer);
- }
-
- if (capabilitiesChanged || statusChanged) {
- // If something changed during update...
- if (updateUi() || !mController.hasPerformedLayout()) {
- // Update the document.
- mController.update();
- }
- }
-
- break;
- }
- }
- }
- }
-
- @Override
- public void onInvalidated() {
- /* do nothing - we always have one fake PDF printer */
- }
- });
-
- // Media size.
- mMediaSizeSpinnerAdapter = new ArrayAdapter<SpinnerItem<MediaSize>>(
- PrintJobConfigActivity.this,
- R.layout.spinner_dropdown_item, R.id.title);
-
- // Color mode.
- mColorModeSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(
- PrintJobConfigActivity.this,
- R.layout.spinner_dropdown_item, R.id.title);
-
- // Orientation
- mOrientationSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(
- PrintJobConfigActivity.this,
- R.layout.spinner_dropdown_item, R.id.title);
- String[] orientationLabels = getResources().getStringArray(
- R.array.orientation_labels);
- mOrientationSpinnerAdapter.add(new SpinnerItem<Integer>(
- ORIENTATION_PORTRAIT, orientationLabels[0]));
- mOrientationSpinnerAdapter.add(new SpinnerItem<Integer>(
- ORIENTATION_LANDSCAPE, orientationLabels[1]));
-
- // Range options
- mRangeOptionsSpinnerAdapter = new ArrayAdapter<SpinnerItem<Integer>>(
- PrintJobConfigActivity.this,
- R.layout.spinner_dropdown_item, R.id.title);
- final int[] rangeOptionsValues = getResources().getIntArray(
- R.array.page_options_values);
- String[] rangeOptionsLabels = getResources().getStringArray(
- R.array.page_options_labels);
- final int rangeOptionsCount = rangeOptionsLabels.length;
- for (int i = 0; i < rangeOptionsCount; i++) {
- mRangeOptionsSpinnerAdapter.add(new SpinnerItem<Integer>(
- rangeOptionsValues[i], rangeOptionsLabels[i]));
- }
-
- showUi(UI_EDITING_PRINT_JOB, null);
- bindUi();
- updateUi();
- }
-
- public void reselectCurrentPrinter() {
- if (mCurrentPrinter != null) {
- // TODO: While the data did not change and we set the adapter
- // to a newly inflated spinner, the latter does not show the
- // current item unless we poke the adapter. This requires more
- // investigation. Maybe an optimization in AdapterView does not
- // call into the adapter if the view is not visible which is the
- // case when we set the adapter.
- mDestinationSpinnerAdapter.notifyDataSetChanged();
- final int position = mDestinationSpinnerAdapter.getPrinterIndex(
- mCurrentPrinter.getId());
- mDestinationSpinner.setSelection(position);
- }
- }
-
- public void refreshCurrentPrinter() {
- PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem();
- if (printer != null) {
- FusedPrintersProvider printersLoader = (FusedPrintersProvider)
- (Loader<?>) getLoaderManager().getLoader(
- LOADER_ID_PRINTERS_LOADER);
- if (printersLoader != null) {
- printersLoader.setTrackedPrinter(printer.getId());
- }
- }
- }
-
- public void addCurrentPrinterToHistory() {
- PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem();
- PrinterId fakePdfPritnerId = mDestinationSpinnerAdapter.mFakePdfPrinter.getId();
- if (printer != null && !printer.getId().equals(fakePdfPritnerId)) {
- FusedPrintersProvider printersLoader = (FusedPrintersProvider)
- (Loader<?>) getLoaderManager().getLoader(
- LOADER_ID_PRINTERS_LOADER);
- if (printersLoader != null) {
- printersLoader.addHistoricalPrinter(printer);
- }
- }
- }
-
- public void updateFromAdvancedOptions(PrintJobInfo printJobInfo) {
- boolean updateContent = false;
-
- // Copies.
- mCopiesEditText.setText(String.valueOf(printJobInfo.getCopies()));
-
- // Media size and orientation
- PrintAttributes attributes = printJobInfo.getAttributes();
- if (!mCurrPrintAttributes.getMediaSize().equals(attributes.getMediaSize())) {
- final int mediaSizeCount = mMediaSizeSpinnerAdapter.getCount();
- for (int i = 0; i < mediaSizeCount; i++) {
- MediaSize mediaSize = mMediaSizeSpinnerAdapter.getItem(i).value;
- if (mediaSize.asPortrait().equals(attributes.getMediaSize().asPortrait())) {
- updateContent = true;
- mCurrPrintAttributes.setMediaSize(attributes.getMediaSize());
- mMediaSizeSpinner.setSelection(i);
- mIgnoreNextMediaSizeChange = true;
- if (attributes.getMediaSize().isPortrait()) {
- mOrientationSpinner.setSelection(0);
- mIgnoreNextOrientationChange = true;
- } else {
- mOrientationSpinner.setSelection(1);
- mIgnoreNextOrientationChange = true;
- }
- break;
- }
- }
- }
-
- // Color mode.
- final int colorMode = attributes.getColorMode();
- if (mCurrPrintAttributes.getColorMode() != colorMode) {
- if (colorMode == PrintAttributes.COLOR_MODE_MONOCHROME) {
- updateContent = true;
- mColorModeSpinner.setSelection(0);
- mIgnoreNextColorChange = true;
- mCurrPrintAttributes.setColorMode(attributes.getColorMode());
- } else if (colorMode == PrintAttributes.COLOR_MODE_COLOR) {
- updateContent = true;
- mColorModeSpinner.setSelection(1);
- mIgnoreNextColorChange = true;
- mCurrPrintAttributes.setColorMode(attributes.getColorMode());
- }
- }
-
- // Range.
- PageRange[] pageRanges = printJobInfo.getPages();
- if (pageRanges != null && pageRanges.length > 0) {
- pageRanges = PageRangeUtils.normalize(pageRanges);
- final int pageRangeCount = pageRanges.length;
- if (pageRangeCount == 1 && pageRanges[0] == PageRange.ALL_PAGES) {
- mRangeOptionsSpinner.setSelection(0);
- } else {
- final int pageCount = mDocument.info.getPageCount();
- if (pageRanges[0].getStart() >= 0
- && pageRanges[pageRanges.length - 1].getEnd() < pageCount) {
- mRangeOptionsSpinner.setSelection(1);
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < pageRangeCount; i++) {
- if (builder.length() > 0) {
- builder.append(',');
- }
- PageRange pageRange = pageRanges[i];
- final int shownStartPage = pageRange.getStart() + 1;
- final int shownEndPage = pageRange.getEnd() + 1;
- builder.append(shownStartPage);
- if (shownStartPage != shownEndPage) {
- builder.append('-');
- builder.append(shownEndPage);
- }
- }
- mPageRangeEditText.setText(builder.toString());
- }
- }
- }
-
- // Update the advanced options.
- mSpoolerProvider.getSpooler().setPrintJobAdvancedOptionsNoPersistence(
- mPrintJobId, printJobInfo.getAdvancedOptions());
-
- // Update the content if needed.
- if (updateContent) {
- mController.update();
- }
- }
-
- public void ensurePrinterSelected(PrinterId printerId) {
- // If the printer is not present maybe the loader is not
- // updated yet. In this case make a note and as soon as
- // the printer appears will will select it.
- if (!selectPrinter(printerId)) {
- mNextPrinterId = printerId;
- }
- }
-
- public boolean selectPrinter(PrinterId printerId) {
- mDestinationSpinnerAdapter.ensurePrinterInVisibleAdapterPosition(printerId);
- final int position = mDestinationSpinnerAdapter.getPrinterIndex(printerId);
- if (position != AdapterView.INVALID_POSITION
- && position != mDestinationSpinner.getSelectedItemPosition()) {
- Object item = mDestinationSpinnerAdapter.getItem(position);
- mCurrentPrinter = (PrinterInfo) item;
- mDestinationSpinner.setSelection(position);
- return true;
- }
- return false;
- }
-
- public void ensureCurrentPrinterSelected() {
- if (mCurrentPrinter != null) {
- selectPrinter(mCurrentPrinter.getId());
- }
- }
-
- public boolean isPrintingToPdf() {
- return mDestinationSpinner.getSelectedItem()
- == mDestinationSpinnerAdapter.mFakePdfPrinter;
- }
-
- public boolean shouldCloseOnTouch(MotionEvent event) {
- if (event.getAction() != MotionEvent.ACTION_DOWN) {
- return false;
- }
-
- final int[] locationInWindow = new int[2];
- mContentContainer.getLocationInWindow(locationInWindow);
-
- final int windowTouchSlop = ViewConfiguration.get(PrintJobConfigActivity.this)
- .getScaledWindowTouchSlop();
- final int eventX = (int) event.getX();
- final int eventY = (int) event.getY();
- final int lenientWindowLeft = locationInWindow[0] - windowTouchSlop;
- final int lenientWindowRight = lenientWindowLeft + mContentContainer.getWidth()
- + windowTouchSlop;
- final int lenientWindowTop = locationInWindow[1] - windowTouchSlop;
- final int lenientWindowBottom = lenientWindowTop + mContentContainer.getHeight()
- + windowTouchSlop;
-
- if (eventX < lenientWindowLeft || eventX > lenientWindowRight
- || eventY < lenientWindowTop || eventY > lenientWindowBottom) {
- return true;
- }
- return false;
- }
-
- public boolean isShwoingGeneratingPrintJobUi() {
- return (mCurrentUi == UI_GENERATING_PRINT_JOB);
- }
-
- public void showUi(int ui, final Runnable postSwitchCallback) {
- if (ui == UI_NONE) {
- throw new IllegalStateException("cannot remove the ui");
- }
-
- if (mCurrentUi == ui) {
- return;
- }
-
- final int oldUi = mCurrentUi;
- mCurrentUi = ui;
-
- switch (oldUi) {
- case UI_NONE: {
- switch (ui) {
- case UI_EDITING_PRINT_JOB: {
- doUiSwitch(R.layout.print_job_config_activity_content_editing);
- registerPrintButtonClickListener();
- if (postSwitchCallback != null) {
- postSwitchCallback.run();
- }
- } break;
-
- case UI_GENERATING_PRINT_JOB: {
- doUiSwitch(R.layout.print_job_config_activity_content_generating);
- registerCancelButtonClickListener();
- if (postSwitchCallback != null) {
- postSwitchCallback.run();
- }
- } break;
- }
- } break;
-
- case UI_EDITING_PRINT_JOB: {
- switch (ui) {
- case UI_GENERATING_PRINT_JOB: {
- animateUiSwitch(R.layout.print_job_config_activity_content_generating,
- new Runnable() {
- @Override
- public void run() {
- registerCancelButtonClickListener();
- if (postSwitchCallback != null) {
- postSwitchCallback.run();
- }
- }
- },
- new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER));
- } break;
-
- case UI_ERROR: {
- animateUiSwitch(R.layout.print_job_config_activity_content_error,
- new Runnable() {
- @Override
- public void run() {
- registerOkButtonClickListener();
- if (postSwitchCallback != null) {
- postSwitchCallback.run();
- }
- }
- },
- new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER));
- } break;
- }
- } break;
-
- case UI_GENERATING_PRINT_JOB: {
- switch (ui) {
- case UI_EDITING_PRINT_JOB: {
- animateUiSwitch(R.layout.print_job_config_activity_content_editing,
- new Runnable() {
- @Override
- public void run() {
- registerPrintButtonClickListener();
- if (postSwitchCallback != null) {
- postSwitchCallback.run();
- }
- }
- },
- new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER));
- } break;
-
- case UI_ERROR: {
- animateUiSwitch(R.layout.print_job_config_activity_content_error,
- new Runnable() {
- @Override
- public void run() {
- registerOkButtonClickListener();
- if (postSwitchCallback != null) {
- postSwitchCallback.run();
- }
- }
- },
- new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER));
- } break;
- }
- } break;
-
- case UI_ERROR: {
- switch (ui) {
- case UI_EDITING_PRINT_JOB: {
- animateUiSwitch(R.layout.print_job_config_activity_content_editing,
- new Runnable() {
- @Override
- public void run() {
- registerPrintButtonClickListener();
- if (postSwitchCallback != null) {
- postSwitchCallback.run();
- }
- }
- },
- new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER));
- } break;
- }
- } break;
- }
- }
-
- private void registerAdvancedPrintOptionsButtonClickListener() {
- Button advancedOptionsButton = (Button) findViewById(R.id.advanced_settings_button);
- advancedOptionsButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- ComponentName serviceName = mCurrentPrinter.getId().getServiceName();
- String activityName = getAdvancedOptionsActivityName(serviceName);
- if (TextUtils.isEmpty(activityName)) {
- return;
- }
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setComponent(new ComponentName(serviceName.getPackageName(),
- activityName));
-
- List<ResolveInfo> resolvedActivities = getPackageManager()
- .queryIntentActivities(intent, 0);
- if (resolvedActivities.isEmpty()) {
- return;
- }
- // The activity is a component name, therefore it is one or none.
- if (resolvedActivities.get(0).activityInfo.exported) {
- PrintJobInfo printJobInfo = mSpoolerProvider.getSpooler().getPrintJobInfo(
- mPrintJobId, PrintManager.APP_ID_ANY);
- intent.putExtra(PrintService.EXTRA_PRINT_JOB_INFO, printJobInfo);
- // TODO: Make this an API for the next release.
- intent.putExtra("android.intent.extra.print.EXTRA_PRINTER_INFO",
- mCurrentPrinter);
- try {
- startActivityForResult(intent,
- ACTIVITY_POPULATE_ADVANCED_PRINT_OPTIONS);
- } catch (ActivityNotFoundException anfe) {
- Log.e(LOG_TAG, "Error starting activity for intent: " + intent, anfe);
- }
- }
- }
- });
- }
-
- private void registerPrintButtonClickListener() {
- Button printButton = (Button) findViewById(R.id.print_button);
- printButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem();
- if (printer != null) {
- mEditor.confirmPrint();
- mController.update();
- if (!printer.equals(mDestinationSpinnerAdapter.mFakePdfPrinter)) {
- mEditor.refreshCurrentPrinter();
- }
- } else {
- mEditor.cancel();
- PrintJobConfigActivity.this.finish();
- }
- }
- });
- }
-
- private void registerCancelButtonClickListener() {
- Button cancelButton = (Button) findViewById(R.id.cancel_button);
- cancelButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (!mController.isWorking()) {
- PrintJobConfigActivity.this.finish();
- }
- mEditor.cancel();
- }
- });
- }
-
- private void registerOkButtonClickListener() {
- Button okButton = (Button) findViewById(R.id.ok_button);
- okButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mEditor.showUi(Editor.UI_EDITING_PRINT_JOB, new Runnable() {
- @Override
- public void run() {
- // Start over with a clean slate.
- mOldPrintAttributes.clear();
- mController.initialize();
- mEditor.initialize();
- mEditor.bindUi();
- mEditor.reselectCurrentPrinter();
- if (!mController.hasPerformedLayout()) {
- mController.update();
- }
- }
- });
- }
- });
- }
-
- private void doUiSwitch(int showLayoutId) {
- ViewGroup contentContainer = (ViewGroup) findViewById(R.id.content_container);
- contentContainer.removeAllViews();
- getLayoutInflater().inflate(showLayoutId, contentContainer, true);
- }
-
- private void animateUiSwitch(int showLayoutId, final Runnable beforeShowNewUiAction,
- final LayoutParams containerParams) {
- // Find everything we will shuffle around.
- final ViewGroup contentContainer = (ViewGroup) findViewById(R.id.content_container);
- final View hidingView = contentContainer.getChildAt(0);
- final View showingView = getLayoutInflater().inflate(showLayoutId,
- null, false);
-
- // First animation - fade out the old content.
- AutoCancellingAnimator.animate(hidingView).alpha(0.0f)
- .withLayer().withEndAction(new Runnable() {
- @Override
- public void run() {
- hidingView.setVisibility(View.INVISIBLE);
-
- // Prepare the new content with correct size and alpha.
- showingView.setMinimumWidth(contentContainer.getWidth());
- showingView.setAlpha(0.0f);
-
- // Compute how to much shrink /stretch the content.
- final int widthSpec = MeasureSpec.makeMeasureSpec(
- contentContainer.getWidth(), MeasureSpec.UNSPECIFIED);
- final int heightSpec = MeasureSpec.makeMeasureSpec(
- contentContainer.getHeight(), MeasureSpec.UNSPECIFIED);
- showingView.measure(widthSpec, heightSpec);
- final float scaleY = (float) showingView.getMeasuredHeight()
- / (float) contentContainer.getHeight();
-
- // Second animation - resize the container.
- AutoCancellingAnimator.animate(contentContainer).scaleY(scaleY)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- // Swap the old and the new content.
- contentContainer.removeAllViews();
- contentContainer.setScaleY(1.0f);
- contentContainer.addView(showingView);
-
- contentContainer.setLayoutParams(containerParams);
-
- beforeShowNewUiAction.run();
-
- // Third animation - show the new content.
- AutoCancellingAnimator.animate(showingView).alpha(1.0f);
- }
- });
- }
- });
- }
-
- public void initialize() {
- mEditorState = EDITOR_STATE_INITIALIZED;
- }
-
- public boolean isCancelled() {
- return mEditorState == EDITOR_STATE_CANCELLED;
- }
-
- public void cancel() {
- mEditorState = EDITOR_STATE_CANCELLED;
- mController.cancel();
- updateUi();
- }
-
- public boolean isDone() {
- return isPrintConfirmed() || isCancelled();
- }
-
- public boolean isPrintConfirmed() {
- return mEditorState == EDITOR_STATE_CONFIRMED_PRINT;
- }
-
- public void confirmPrint() {
- addCurrentPrinterToHistory();
- mEditorState = EDITOR_STATE_CONFIRMED_PRINT;
- showUi(UI_GENERATING_PRINT_JOB, null);
- }
-
- public PageRange[] getRequestedPages() {
- if (hasErrors()) {
- return null;
- }
- if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
- List<PageRange> pageRanges = new ArrayList<PageRange>();
- mStringCommaSplitter.setString(mPageRangeEditText.getText().toString());
-
- while (mStringCommaSplitter.hasNext()) {
- String range = mStringCommaSplitter.next().trim();
- if (TextUtils.isEmpty(range)) {
- continue;
- }
- final int dashIndex = range.indexOf('-');
- final int fromIndex;
- final int toIndex;
-
- if (dashIndex > 0) {
- fromIndex = Integer.parseInt(range.substring(0, dashIndex).trim()) - 1;
- // It is possible that the dash is at the end since the input
- // verification can has to allow the user to keep entering if
- // this would lead to a valid input. So we handle this.
- toIndex = (dashIndex < range.length() - 1)
- ? Integer.parseInt(range.substring(dashIndex + 1,
- range.length()).trim()) - 1 : fromIndex;
- } else {
- fromIndex = toIndex = Integer.parseInt(range) - 1;
- }
-
- PageRange pageRange = new PageRange(Math.min(fromIndex, toIndex),
- Math.max(fromIndex, toIndex));
- pageRanges.add(pageRange);
- }
-
- PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
- pageRanges.toArray(pageRangesArray);
-
- return PageRangeUtils.normalize(pageRangesArray);
- }
-
- return ALL_PAGES_ARRAY;
- }
-
- private void bindUi() {
- if (mCurrentUi != UI_EDITING_PRINT_JOB) {
- return;
- }
-
- // Content container
- mContentContainer = findViewById(R.id.content_container);
-
- // Copies
- mCopiesEditText = (EditText) findViewById(R.id.copies_edittext);
- mCopiesEditText.setOnFocusChangeListener(mFocusListener);
- mCopiesEditText.setText(MIN_COPIES_STRING);
- mCopiesEditText.setSelection(mCopiesEditText.getText().length());
- mCopiesEditText.addTextChangedListener(mCopiesTextWatcher);
- if (!TextUtils.equals(mCopiesEditText.getText(), MIN_COPIES_STRING)) {
- mIgnoreNextCopiesChange = true;
- }
- mSpoolerProvider.getSpooler().setPrintJobCopiesNoPersistence(
- mPrintJobId, MIN_COPIES);
-
- // Destination.
- mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner);
- mDestinationSpinner.setDropDownWidth(ViewGroup.LayoutParams.MATCH_PARENT);
- mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter);
- mDestinationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
- if (mDestinationSpinnerAdapter.getCount() > 0) {
- mIgnoreNextDestinationChange = true;
- }
-
- // Media size.
- mMediaSizeSpinner = (Spinner) findViewById(R.id.paper_size_spinner);
- mMediaSizeSpinner.setAdapter(mMediaSizeSpinnerAdapter);
- mMediaSizeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
- if (mMediaSizeSpinnerAdapter.getCount() > 0) {
- mOldMediaSizeSelectionIndex = 0;
- }
-
- // Color mode.
- mColorModeSpinner = (Spinner) findViewById(R.id.color_spinner);
- mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter);
- mColorModeSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
- if (mColorModeSpinnerAdapter.getCount() > 0) {
- mOldColorModeSelectionIndex = 0;
- }
-
- // Orientation
- mOrientationSpinner = (Spinner) findViewById(R.id.orientation_spinner);
- mOrientationSpinner.setAdapter(mOrientationSpinnerAdapter);
- mOrientationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
- if (mOrientationSpinnerAdapter.getCount() > 0) {
- mIgnoreNextOrientationChange = true;
- }
-
- // Range options
- mRangeOptionsTitle = (TextView) findViewById(R.id.range_options_title);
- mRangeOptionsSpinner = (Spinner) findViewById(R.id.range_options_spinner);
- mRangeOptionsSpinner.setAdapter(mRangeOptionsSpinnerAdapter);
- mRangeOptionsSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
- if (mRangeOptionsSpinnerAdapter.getCount() > 0) {
- mIgnoreNextRangeOptionChange = true;
- }
-
- // Page range
- mPageRangeTitle = (TextView) findViewById(R.id.page_range_title);
- mPageRangeEditText = (EditText) findViewById(R.id.page_range_edittext);
- mPageRangeEditText.setOnFocusChangeListener(mFocusListener);
- mPageRangeEditText.addTextChangedListener(mRangeTextWatcher);
-
- // Advanced options button.
- mAdvancedPrintOptionsContainer = findViewById(R.id.advanced_settings_container);
- mAdvancedOptionsButton = (Button) findViewById(R.id.advanced_settings_button);
- registerAdvancedPrintOptionsButtonClickListener();
-
- // Print button
- mPrintButton = (Button) findViewById(R.id.print_button);
- registerPrintButtonClickListener();
- }
-
- public boolean updateUi() {
- if (mCurrentUi != UI_EDITING_PRINT_JOB) {
- return false;
- }
- if (isPrintConfirmed() || isCancelled()) {
- mDestinationSpinner.setEnabled(false);
- mCopiesEditText.setEnabled(false);
- mMediaSizeSpinner.setEnabled(false);
- mColorModeSpinner.setEnabled(false);
- mOrientationSpinner.setEnabled(false);
- mRangeOptionsSpinner.setEnabled(false);
- mPageRangeEditText.setEnabled(false);
- mPrintButton.setEnabled(false);
- mAdvancedOptionsButton.setEnabled(false);
- return false;
- }
-
- // If a printer with capabilities is selected, then we enabled all options.
- boolean allOptionsEnabled = false;
- final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
- if (selectedIndex >= 0) {
- Object item = mDestinationSpinnerAdapter.getItem(selectedIndex);
- if (item instanceof PrinterInfo) {
- PrinterInfo printer = (PrinterInfo) item;
- if (printer.getCapabilities() != null
- && printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE) {
- allOptionsEnabled = true;
- }
- }
- }
-
- if (!allOptionsEnabled) {
- mCopiesEditText.setEnabled(false);
- mMediaSizeSpinner.setEnabled(false);
- mColorModeSpinner.setEnabled(false);
- mOrientationSpinner.setEnabled(false);
- mRangeOptionsSpinner.setEnabled(false);
- mPageRangeEditText.setEnabled(false);
- mPrintButton.setEnabled(false);
- mAdvancedOptionsButton.setEnabled(false);
- return false;
- } else {
- boolean someAttributeSelectionChanged = false;
-
- PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem();
- PrinterCapabilitiesInfo capabilities = printer.getCapabilities();
- PrintAttributes defaultAttributes = printer.getCapabilities().getDefaults();
-
- // Media size.
- // Sort the media sizes based on the current locale.
- List<MediaSize> mediaSizes = new ArrayList<MediaSize>(capabilities.getMediaSizes());
- Collections.sort(mediaSizes, mMediaSizeComparator);
-
- // If the media sizes changed, we update the adapter and the spinner.
- boolean mediaSizesChanged = false;
- final int mediaSizeCount = mediaSizes.size();
- if (mediaSizeCount != mMediaSizeSpinnerAdapter.getCount()) {
- mediaSizesChanged = true;
- } else {
- for (int i = 0; i < mediaSizeCount; i++) {
- if (!mediaSizes.get(i).equals(mMediaSizeSpinnerAdapter.getItem(i).value)) {
- mediaSizesChanged = true;
- break;
- }
- }
- }
- if (mediaSizesChanged) {
- // Remember the old media size to try selecting it again.
- int oldMediaSizeNewIndex = AdapterView.INVALID_POSITION;
- MediaSize oldMediaSize = mCurrPrintAttributes.getMediaSize();
-
- // Rebuild the adapter data.
- mMediaSizeSpinnerAdapter.clear();
- for (int i = 0; i < mediaSizeCount; i++) {
- MediaSize mediaSize = mediaSizes.get(i);
- if (mediaSize.asPortrait().equals(oldMediaSize.asPortrait())) {
- // Update the index of the old selection.
- oldMediaSizeNewIndex = i;
- }
- mMediaSizeSpinnerAdapter.add(new SpinnerItem<MediaSize>(
- mediaSize, mediaSize.getLabel(getPackageManager())));
- }
-
- mMediaSizeSpinner.setEnabled(true);
-
- if (oldMediaSizeNewIndex != AdapterView.INVALID_POSITION) {
- // Select the old media size - nothing really changed.
- setMediaSizeSpinnerSelectionNoCallback(oldMediaSizeNewIndex);
- } else {
- // Select the first or the default and mark if selection changed.
- final int mediaSizeIndex = Math.max(mediaSizes.indexOf(
- defaultAttributes.getMediaSize()), 0);
- setMediaSizeSpinnerSelectionNoCallback(mediaSizeIndex);
- if (oldMediaSize.isPortrait()) {
- mCurrPrintAttributes.setMediaSize(mMediaSizeSpinnerAdapter
- .getItem(mediaSizeIndex).value.asPortrait());
- } else {
- mCurrPrintAttributes.setMediaSize(mMediaSizeSpinnerAdapter
- .getItem(mediaSizeIndex).value.asLandscape());
- }
- someAttributeSelectionChanged = true;
- }
- }
- mMediaSizeSpinner.setEnabled(true);
-
- // Color mode.
- final int colorModes = capabilities.getColorModes();
-
- // If the color modes changed, we update the adapter and the spinner.
- boolean colorModesChanged = false;
- if (Integer.bitCount(colorModes) != mColorModeSpinnerAdapter.getCount()) {
- colorModesChanged = true;
- } else {
- int remainingColorModes = colorModes;
- int adapterIndex = 0;
- while (remainingColorModes != 0) {
- final int colorBitOffset = Integer.numberOfTrailingZeros(
- remainingColorModes);
- final int colorMode = 1 << colorBitOffset;
- remainingColorModes &= ~colorMode;
- if (colorMode != mColorModeSpinnerAdapter.getItem(adapterIndex).value) {
- colorModesChanged = true;
- break;
- }
- adapterIndex++;
- }
- }
- if (colorModesChanged) {
- // Remember the old color mode to try selecting it again.
- int oldColorModeNewIndex = AdapterView.INVALID_POSITION;
- final int oldColorMode = mCurrPrintAttributes.getColorMode();
-
- // Rebuild the adapter data.
- mColorModeSpinnerAdapter.clear();
- String[] colorModeLabels = getResources().getStringArray(
- R.array.color_mode_labels);
- int remainingColorModes = colorModes;
- while (remainingColorModes != 0) {
- final int colorBitOffset = Integer.numberOfTrailingZeros(
- remainingColorModes);
- final int colorMode = 1 << colorBitOffset;
- if (colorMode == oldColorMode) {
- // Update the index of the old selection.
- oldColorModeNewIndex = colorBitOffset;
- }
- remainingColorModes &= ~colorMode;
- mColorModeSpinnerAdapter.add(new SpinnerItem<Integer>(colorMode,
- colorModeLabels[colorBitOffset]));
- }
- mColorModeSpinner.setEnabled(true);
- if (oldColorModeNewIndex != AdapterView.INVALID_POSITION) {
- // Select the old color mode - nothing really changed.
- setColorModeSpinnerSelectionNoCallback(oldColorModeNewIndex);
- } else {
- final int selectedColorMode = colorModes & defaultAttributes.getColorMode();
- final int itemCount = mColorModeSpinnerAdapter.getCount();
- for (int i = 0; i < itemCount; i++) {
- SpinnerItem<Integer> item = mColorModeSpinnerAdapter.getItem(i);
- if (selectedColorMode == item.value) {
- setColorModeSpinnerSelectionNoCallback(i);
- mCurrPrintAttributes.setColorMode(selectedColorMode);
- someAttributeSelectionChanged = true;
- }
- }
- }
- }
- mColorModeSpinner.setEnabled(true);
-
- // Orientation
- MediaSize mediaSize = mCurrPrintAttributes.getMediaSize();
- if (mediaSize.isPortrait()
- && mOrientationSpinner.getSelectedItemPosition() != 0) {
- mIgnoreNextOrientationChange = true;
- mOrientationSpinner.setSelection(0);
- } else if (!mediaSize.isPortrait()
- && mOrientationSpinner.getSelectedItemPosition() != 1) {
- mIgnoreNextOrientationChange = true;
- mOrientationSpinner.setSelection(1);
- }
- mOrientationSpinner.setEnabled(true);
-
- // Range options
- PrintDocumentInfo info = mDocument.info;
- if (info != null && info.getPageCount() > 0) {
- if (info.getPageCount() == 1) {
- mRangeOptionsSpinner.setEnabled(false);
- } else {
- mRangeOptionsSpinner.setEnabled(true);
- if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
- if (!mPageRangeEditText.isEnabled()) {
- mPageRangeEditText.setEnabled(true);
- mPageRangeEditText.setVisibility(View.VISIBLE);
- mPageRangeTitle.setVisibility(View.VISIBLE);
- mPageRangeEditText.requestFocus();
- InputMethodManager imm = (InputMethodManager)
- getSystemService(INPUT_METHOD_SERVICE);
- imm.showSoftInput(mPageRangeEditText, 0);
- }
- } else {
- mPageRangeEditText.setEnabled(false);
- mPageRangeEditText.setVisibility(View.INVISIBLE);
- mPageRangeTitle.setVisibility(View.INVISIBLE);
- }
- }
- final int pageCount = mDocument.info.getPageCount();
- String title = (pageCount != PrintDocumentInfo.PAGE_COUNT_UNKNOWN)
- ? getString(R.string.label_pages, String.valueOf(pageCount))
- : getString(R.string.page_count_unknown);
- mRangeOptionsTitle.setText(title);
- } else {
- if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
- mIgnoreNextRangeOptionChange = true;
- mRangeOptionsSpinner.setSelection(0);
- }
- mRangeOptionsSpinner.setEnabled(false);
- mRangeOptionsTitle.setText(getString(R.string.page_count_unknown));
- mPageRangeEditText.setEnabled(false);
- mPageRangeEditText.setVisibility(View.INVISIBLE);
- mPageRangeTitle.setVisibility(View.INVISIBLE);
- }
-
- // Advanced print options
- ComponentName serviceName = mCurrentPrinter.getId().getServiceName();
- if (!TextUtils.isEmpty(getAdvancedOptionsActivityName(serviceName))) {
- mAdvancedPrintOptionsContainer.setVisibility(View.VISIBLE);
- mAdvancedOptionsButton.setEnabled(true);
- } else {
- mAdvancedPrintOptionsContainer.setVisibility(View.GONE);
- mAdvancedOptionsButton.setEnabled(false);
- }
-
- // Print
- if (mDestinationSpinner.getSelectedItemId()
- != DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF) {
- String newText = getString(R.string.print_button);
- if (!TextUtils.equals(newText, mPrintButton.getText())) {
- mPrintButton.setText(R.string.print_button);
- }
- } else {
- String newText = getString(R.string.save_button);
- if (!TextUtils.equals(newText, mPrintButton.getText())) {
- mPrintButton.setText(R.string.save_button);
- }
- }
- if ((mRangeOptionsSpinner.getSelectedItemPosition() == 1
- && (TextUtils.isEmpty(mPageRangeEditText.getText()) || hasErrors()))
- || (mRangeOptionsSpinner.getSelectedItemPosition() == 0
- && (!mController.hasPerformedLayout() || hasErrors()))) {
- mPrintButton.setEnabled(false);
- } else {
- mPrintButton.setEnabled(true);
- }
-
- // Copies
- if (mDestinationSpinner.getSelectedItemId()
- != DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF) {
- mCopiesEditText.setEnabled(true);
- } else {
- mCopiesEditText.setEnabled(false);
- }
- if (mCopiesEditText.getError() == null
- && TextUtils.isEmpty(mCopiesEditText.getText())) {
- mIgnoreNextCopiesChange = true;
- mCopiesEditText.setText(String.valueOf(MIN_COPIES));
- mCopiesEditText.requestFocus();
- }
-
- return someAttributeSelectionChanged;
- }
- }
-
- private String getAdvancedOptionsActivityName(ComponentName serviceName) {
- PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE);
- List<PrintServiceInfo> printServices = printManager.getEnabledPrintServices();
- final int printServiceCount = printServices.size();
- for (int i = 0; i < printServiceCount; i ++) {
- PrintServiceInfo printServiceInfo = printServices.get(i);
- ServiceInfo serviceInfo = printServiceInfo.getResolveInfo().serviceInfo;
- if (serviceInfo.name.equals(serviceName.getClassName())
- && serviceInfo.packageName.equals(serviceName.getPackageName())) {
- return printServiceInfo.getAdvancedOptionsActivityName();
- }
- }
- return null;
- }
-
- private void setMediaSizeSpinnerSelectionNoCallback(int position) {
- if (mMediaSizeSpinner.getSelectedItemPosition() != position) {
- mOldMediaSizeSelectionIndex = position;
- mMediaSizeSpinner.setSelection(position);
- }
- }
-
- private void setColorModeSpinnerSelectionNoCallback(int position) {
- if (mColorModeSpinner.getSelectedItemPosition() != position) {
- mOldColorModeSelectionIndex = position;
- mColorModeSpinner.setSelection(position);
- }
- }
-
- private void startSelectPrinterActivity() {
- Intent intent = new Intent(PrintJobConfigActivity.this,
- SelectPrinterActivity.class);
- startActivityForResult(intent, ACTIVITY_REQUEST_SELECT_PRINTER);
- }
-
- private boolean hasErrors() {
- if (mCopiesEditText.getError() != null) {
- return true;
- }
- return mPageRangeEditText.getVisibility() == View.VISIBLE
- && mPageRangeEditText.getError() != null;
- }
-
- private final class SpinnerItem<T> {
- final T value;
- CharSequence label;
-
- public SpinnerItem(T value, CharSequence label) {
- this.value = value;
- this.label = label;
- }
-
- public String toString() {
- return label.toString();
- }
- }
-
- private final class WaitForPrinterCapabilitiesTimeout implements Runnable {
- private static final long GET_CAPABILITIES_TIMEOUT_MILLIS = 10000; // 10sec
-
- private boolean mIsPosted;
-
- public void post() {
- if (!mIsPosted) {
- mDestinationSpinner.postDelayed(this,
- GET_CAPABILITIES_TIMEOUT_MILLIS);
- mIsPosted = true;
- }
- }
-
- public void remove() {
- if (mIsPosted) {
- mIsPosted = false;
- mDestinationSpinner.removeCallbacks(this);
- }
- }
-
- public boolean isPosted() {
- return mIsPosted;
- }
-
- @Override
- public void run() {
- mIsPosted = false;
- if (mDestinationSpinner.getSelectedItemPosition() >= 0) {
- View itemView = mDestinationSpinner.getSelectedView();
- TextView titleView = (TextView) itemView.findViewById(R.id.subtitle);
- try {
- PackageInfo packageInfo = getPackageManager().getPackageInfo(
- mCurrentPrinter.getId().getServiceName().getPackageName(), 0);
- CharSequence service = packageInfo.applicationInfo.loadLabel(
- getPackageManager());
- String subtitle = getString(R.string.printer_unavailable, service.toString());
- titleView.setText(subtitle);
- } catch (NameNotFoundException nnfe) {
- /* ignore */
- }
- }
- }
- }
-
- private final class DestinationAdapter extends BaseAdapter
- implements LoaderManager.LoaderCallbacks<List<PrinterInfo>>{
- private final List<PrinterInfo> mPrinters = new ArrayList<PrinterInfo>();
-
- private PrinterInfo mFakePdfPrinter;
-
- public DestinationAdapter() {
- getLoaderManager().initLoader(LOADER_ID_PRINTERS_LOADER, null, this);
- }
-
- public int getPrinterIndex(PrinterId printerId) {
- for (int i = 0; i < getCount(); i++) {
- PrinterInfo printer = (PrinterInfo) getItem(i);
- if (printer != null && printer.getId().equals(printerId)) {
- return i;
- }
- }
- return AdapterView.INVALID_POSITION;
- }
-
- public void ensurePrinterInVisibleAdapterPosition(PrinterId printerId) {
- final int printerCount = mPrinters.size();
- for (int i = 0; i < printerCount; i++) {
- PrinterInfo printer = (PrinterInfo) mPrinters.get(i);
- if (printer.getId().equals(printerId)) {
- // If already in the list - do nothing.
- if (i < getCount() - 2) {
- return;
- }
- // Else replace the last one (two items are not printers).
- final int lastPrinterIndex = getCount() - 3;
- mPrinters.set(i, mPrinters.get(lastPrinterIndex));
- mPrinters.set(lastPrinterIndex, printer);
- notifyDataSetChanged();
- return;
- }
- }
- }
-
- @Override
- public int getCount() {
- if (mFakePdfPrinter == null) {
- return 0;
- }
- return Math.min(mPrinters.size() + 2, DEST_ADAPTER_MAX_ITEM_COUNT);
- }
-
- @Override
- public boolean isEnabled(int position) {
- Object item = getItem(position);
- if (item instanceof PrinterInfo) {
- PrinterInfo printer = (PrinterInfo) item;
- return printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE;
- }
- return true;
- }
-
- @Override
- public Object getItem(int position) {
- if (mPrinters.isEmpty()) {
- if (position == 0 && mFakePdfPrinter != null) {
- return mFakePdfPrinter;
- }
- } else {
- if (position < 1) {
- return mPrinters.get(position);
- }
- if (position == 1 && mFakePdfPrinter != null) {
- return mFakePdfPrinter;
- }
- if (position < getCount() - 1) {
- return mPrinters.get(position - 1);
- }
- }
- return null;
- }
-
- @Override
- public long getItemId(int position) {
- if (mPrinters.isEmpty()) {
- if (mFakePdfPrinter != null) {
- if (position == 0) {
- return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF;
- } else if (position == 1) {
- return DEST_ADAPTER_ITEM_ID_ALL_PRINTERS;
- }
- }
- } else {
- if (position == 1 && mFakePdfPrinter != null) {
- return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF;
- }
- if (position == getCount() - 1) {
- return DEST_ADAPTER_ITEM_ID_ALL_PRINTERS;
- }
- }
- return position;
- }
-
- @Override
- public View getDropDownView(int position, View convertView,
- ViewGroup parent) {
- View view = getView(position, convertView, parent);
- view.setEnabled(isEnabled(position));
- return view;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView == null) {
- convertView = getLayoutInflater().inflate(
- R.layout.printer_dropdown_item, parent, false);
- }
-
- CharSequence title = null;
- CharSequence subtitle = null;
- Drawable icon = null;
-
- if (mPrinters.isEmpty()) {
- if (position == 0 && mFakePdfPrinter != null) {
- PrinterInfo printer = (PrinterInfo) getItem(position);
- title = printer.getName();
- } else if (position == 1) {
- title = getString(R.string.all_printers);
- }
- } else {
- if (position == 1 && mFakePdfPrinter != null) {
- PrinterInfo printer = (PrinterInfo) getItem(position);
- title = printer.getName();
- } else if (position == getCount() - 1) {
- title = getString(R.string.all_printers);
- } else {
- PrinterInfo printer = (PrinterInfo) getItem(position);
- title = printer.getName();
- try {
- PackageInfo packageInfo = getPackageManager().getPackageInfo(
- printer.getId().getServiceName().getPackageName(), 0);
- subtitle = packageInfo.applicationInfo.loadLabel(getPackageManager());
- icon = packageInfo.applicationInfo.loadIcon(getPackageManager());
- } catch (NameNotFoundException nnfe) {
- /* ignore */
- }
- }
- }
-
- TextView titleView = (TextView) convertView.findViewById(R.id.title);
- titleView.setText(title);
-
- TextView subtitleView = (TextView) convertView.findViewById(R.id.subtitle);
- if (!TextUtils.isEmpty(subtitle)) {
- subtitleView.setText(subtitle);
- subtitleView.setVisibility(View.VISIBLE);
- } else {
- subtitleView.setText(null);
- subtitleView.setVisibility(View.GONE);
- }
-
- ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
- if (icon != null) {
- iconView.setImageDrawable(icon);
- iconView.setVisibility(View.VISIBLE);
- } else {
- iconView.setVisibility(View.INVISIBLE);
- }
-
- return convertView;
- }
-
- @Override
- public Loader<List<PrinterInfo>> onCreateLoader(int id, Bundle args) {
- if (id == LOADER_ID_PRINTERS_LOADER) {
- return new FusedPrintersProvider(PrintJobConfigActivity.this);
- }
- return null;
- }
-
- @Override
- public void onLoadFinished(Loader<List<PrinterInfo>> loader,
- List<PrinterInfo> printers) {
- // If this is the first load, create the fake PDF printer.
- // We do this to avoid flicker where the PDF printer is the
- // only one and as soon as the loader loads the favorites
- // it gets switched. Not a great user experience.
- if (mFakePdfPrinter == null) {
- mCurrentPrinter = mFakePdfPrinter = createFakePdfPrinter();
- updatePrintAttributes(mCurrentPrinter.getCapabilities());
- updateUi();
- }
-
- // We rearrange the printers if the user selects a printer
- // not shown in the initial short list. Therefore, we have
- // to keep the printer order.
-
- // No old printers - do not bother keeping their position.
- if (mPrinters.isEmpty()) {
- mPrinters.addAll(printers);
- mEditor.ensureCurrentPrinterSelected();
- notifyDataSetChanged();
- return;
- }
-
- // Add the new printers to a map.
- ArrayMap<PrinterId, PrinterInfo> newPrintersMap =
- new ArrayMap<PrinterId, PrinterInfo>();
- final int printerCount = printers.size();
- for (int i = 0; i < printerCount; i++) {
- PrinterInfo printer = printers.get(i);
- newPrintersMap.put(printer.getId(), printer);
- }
-
- List<PrinterInfo> newPrinters = new ArrayList<PrinterInfo>();
-
- // Update printers we already have.
- final int oldPrinterCount = mPrinters.size();
- for (int i = 0; i < oldPrinterCount; i++) {
- PrinterId oldPrinterId = mPrinters.get(i).getId();
- PrinterInfo updatedPrinter = newPrintersMap.remove(oldPrinterId);
- if (updatedPrinter != null) {
- newPrinters.add(updatedPrinter);
- }
- }
-
- // Add the rest of the new printers, i.e. what is left.
- newPrinters.addAll(newPrintersMap.values());
-
- mPrinters.clear();
- mPrinters.addAll(newPrinters);
-
- mEditor.ensureCurrentPrinterSelected();
- notifyDataSetChanged();
- }
-
- @Override
- public void onLoaderReset(Loader<List<PrinterInfo>> loader) {
- mPrinters.clear();
- notifyDataSetInvalidated();
- }
-
-
- private PrinterInfo createFakePdfPrinter() {
- MediaSize defaultMediaSize = MediaSizeUtils.getDefault(PrintJobConfigActivity.this);
-
- PrinterId printerId = new PrinterId(getComponentName(), "PDF printer");
-
- PrinterCapabilitiesInfo.Builder builder =
- new PrinterCapabilitiesInfo.Builder(printerId);
-
- String[] mediaSizeIds = getResources().getStringArray(
- R.array.pdf_printer_media_sizes);
- final int mediaSizeIdCount = mediaSizeIds.length;
- for (int i = 0; i < mediaSizeIdCount; i++) {
- String id = mediaSizeIds[i];
- MediaSize mediaSize = MediaSize.getStandardMediaSizeById(id);
- builder.addMediaSize(mediaSize, mediaSize.equals(defaultMediaSize));
- }
-
- builder.addResolution(new Resolution("PDF resolution", "PDF resolution",
- 300, 300), true);
- builder.setColorModes(PrintAttributes.COLOR_MODE_COLOR
- | PrintAttributes.COLOR_MODE_MONOCHROME,
- PrintAttributes.COLOR_MODE_COLOR);
-
- return new PrinterInfo.Builder(printerId, getString(R.string.save_as_pdf),
- PrinterInfo.STATUS_IDLE)
- .setCapabilities(builder.build())
- .build();
- }
- }
- }
-
- /**
- * An instance of this class class is intended to be the first focusable
- * in a layout to which the system automatically gives focus. It performs
- * some voodoo to avoid the first tap on it to start an edit mode, rather
- * to bring up the IME, i.e. to get the behavior as if the view was not
- * focused.
- */
- public static final class CustomEditText extends EditText {
- private boolean mClickedBeforeFocus;
- private CharSequence mError;
-
- public CustomEditText(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- public boolean performClick() {
- super.performClick();
- if (isFocused() && !mClickedBeforeFocus) {
- clearFocus();
- requestFocus();
- }
- mClickedBeforeFocus = true;
- return true;
- }
-
- @Override
- public CharSequence getError() {
- return mError;
- }
-
- @Override
- public void setError(CharSequence error, Drawable icon) {
- setCompoundDrawables(null, null, icon, null);
- mError = error;
- }
-
- protected void onFocusChanged(boolean gainFocus, int direction,
- Rect previouslyFocusedRect) {
- if (!gainFocus) {
- mClickedBeforeFocus = false;
- }
- super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
- }
- }
-
- private static final class Document {
- public PrintDocumentInfo info;
- public PageRange[] pages;
- }
-
- private static final class PageRangeUtils {
-
- private static final Comparator<PageRange> sComparator = new Comparator<PageRange>() {
- @Override
- public int compare(PageRange lhs, PageRange rhs) {
- return lhs.getStart() - rhs.getStart();
- }
- };
-
- private PageRangeUtils() {
- throw new UnsupportedOperationException();
- }
-
- public static boolean contains(PageRange[] ourRanges, PageRange[] otherRanges) {
- if (ourRanges == null || otherRanges == null) {
- return false;
- }
-
- if (ourRanges.length == 1
- && PageRange.ALL_PAGES.equals(ourRanges[0])) {
- return true;
- }
-
- ourRanges = normalize(ourRanges);
- otherRanges = normalize(otherRanges);
-
- // Note that the code below relies on the ranges being normalized
- // which is they contain monotonically increasing non-intersecting
- // subranges whose start is less that or equal to the end.
- int otherRangeIdx = 0;
- final int ourRangeCount = ourRanges.length;
- final int otherRangeCount = otherRanges.length;
- for (int ourRangeIdx = 0; ourRangeIdx < ourRangeCount; ourRangeIdx++) {
- PageRange ourRange = ourRanges[ourRangeIdx];
- for (; otherRangeIdx < otherRangeCount; otherRangeIdx++) {
- PageRange otherRange = otherRanges[otherRangeIdx];
- if (otherRange.getStart() > ourRange.getEnd()) {
- break;
- }
- if (otherRange.getStart() < ourRange.getStart()
- || otherRange.getEnd() > ourRange.getEnd()) {
- return false;
- }
- }
- }
- if (otherRangeIdx < otherRangeCount) {
- return false;
- }
- return true;
- }
-
- public static PageRange[] normalize(PageRange[] pageRanges) {
- if (pageRanges == null) {
- return null;
- }
- final int oldRangeCount = pageRanges.length;
- if (oldRangeCount <= 1) {
- return pageRanges;
- }
- Arrays.sort(pageRanges, sComparator);
- int newRangeCount = 1;
- for (int i = 0; i < oldRangeCount - 1; i++) {
- newRangeCount++;
- PageRange currentRange = pageRanges[i];
- PageRange nextRange = pageRanges[i + 1];
- if (currentRange.getEnd() + 1 >= nextRange.getStart()) {
- newRangeCount--;
- pageRanges[i] = null;
- pageRanges[i + 1] = new PageRange(currentRange.getStart(),
- Math.max(currentRange.getEnd(), nextRange.getEnd()));
- }
- }
- if (newRangeCount == oldRangeCount) {
- return pageRanges;
- }
- return Arrays.copyOfRange(pageRanges, oldRangeCount - newRangeCount,
- oldRangeCount);
- }
-
- public static void offset(PageRange[] pageRanges, int offset) {
- if (offset == 0) {
- return;
- }
- final int pageRangeCount = pageRanges.length;
- for (int i = 0; i < pageRangeCount; i++) {
- final int start = pageRanges[i].getStart() + offset;
- final int end = pageRanges[i].getEnd() + offset;
- pageRanges[i] = new PageRange(start, end);
- }
- }
- }
-
- private static final class AutoCancellingAnimator
- implements OnAttachStateChangeListener, Runnable {
-
- private ViewPropertyAnimator mAnimator;
-
- private boolean mCancelled;
- private Runnable mEndCallback;
-
- public static AutoCancellingAnimator animate(View view) {
- ViewPropertyAnimator animator = view.animate();
- AutoCancellingAnimator cancellingWrapper =
- new AutoCancellingAnimator(animator);
- view.addOnAttachStateChangeListener(cancellingWrapper);
- return cancellingWrapper;
- }
-
- private AutoCancellingAnimator(ViewPropertyAnimator animator) {
- mAnimator = animator;
- }
-
- public AutoCancellingAnimator alpha(float alpha) {
- mAnimator = mAnimator.alpha(alpha);
- return this;
- }
-
- public void cancel() {
- mAnimator.cancel();
- }
-
- public AutoCancellingAnimator withLayer() {
- mAnimator = mAnimator.withLayer();
- return this;
- }
-
- public AutoCancellingAnimator withEndAction(Runnable callback) {
- mEndCallback = callback;
- mAnimator = mAnimator.withEndAction(this);
- return this;
- }
-
- public AutoCancellingAnimator scaleY(float scale) {
- mAnimator = mAnimator.scaleY(scale);
- return this;
- }
-
- @Override
- public void onViewAttachedToWindow(View v) {
- /* do nothing */
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- cancel();
- }
-
- @Override
- public void run() {
- if (!mCancelled) {
- mEndCallback.run();
- }
- }
- }
-
- private static final class PrintSpoolerProvider implements ServiceConnection {
- private final Context mContext;
- private final Runnable mCallback;
-
- private PrintSpoolerService mSpooler;
-
- public PrintSpoolerProvider(Context context, Runnable callback) {
- mContext = context;
- mCallback = callback;
- Intent intent = new Intent(mContext, PrintSpoolerService.class);
- mContext.bindService(intent, this, 0);
- }
-
- public PrintSpoolerService getSpooler() {
- return mSpooler;
- }
-
- public void destroy() {
- if (mSpooler != null) {
- mContext.unbindService(this);
- }
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- mSpooler = ((PrintSpoolerService.PrintSpooler) service).getService();
- if (mSpooler != null) {
- mCallback.run();
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- /* do noting - we are in the same process */
- }
- }
-
- private static final class PrintDocumentAdapterObserver
- extends IPrintDocumentAdapterObserver.Stub {
- private final WeakReference<PrintJobConfigActivity> mWeakActvity;
-
- public PrintDocumentAdapterObserver(PrintJobConfigActivity activity) {
- mWeakActvity = new WeakReference<PrintJobConfigActivity>(activity);
- }
-
- @Override
- public void onDestroy() {
- final PrintJobConfigActivity activity = mWeakActvity.get();
- if (activity != null) {
- activity.mController.mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (activity.mController != null) {
- activity.mController.cancel();
- }
- if (activity.mEditor != null) {
- activity.mEditor.cancel();
- }
- activity.finish();
- }
- });
- }
- }
- }
-}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
deleted file mode 100644
index d9ccb5d..0000000
--- a/packages/PrintSpooler/src/com/android/printspooler/RemotePrintDocumentAdapter.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.printspooler;
-
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.print.ILayoutResultCallback;
-import android.print.IPrintDocumentAdapter;
-import android.print.IWriteResultCallback;
-import android.print.PageRange;
-import android.print.PrintAttributes;
-import android.util.Log;
-
-import libcore.io.IoUtils;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * This class represents a remote print document adapter instance.
- */
-final class RemotePrintDocumentAdapter {
- private static final String LOG_TAG = "RemotePrintDocumentAdapter";
-
- private static final boolean DEBUG = false;
-
- private final IPrintDocumentAdapter mRemoteInterface;
-
- private final File mFile;
-
- public RemotePrintDocumentAdapter(IPrintDocumentAdapter printAdatper, File file) {
- mRemoteInterface = printAdatper;
- mFile = file;
- }
-
- public void start() {
- if (DEBUG) {
- Log.i(LOG_TAG, "start()");
- }
- try {
- mRemoteInterface.start();
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling start()", re);
- }
- }
-
- public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
- ILayoutResultCallback callback, Bundle metadata, int sequence) {
- if (DEBUG) {
- Log.i(LOG_TAG, "layout()");
- }
- try {
- mRemoteInterface.layout(oldAttributes, newAttributes, callback, metadata, sequence);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling layout()", re);
- }
- }
-
- public void write(final PageRange[] pages, final IWriteResultCallback callback,
- final int sequence) {
- if (DEBUG) {
- Log.i(LOG_TAG, "write()");
- }
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- InputStream in = null;
- OutputStream out = null;
- ParcelFileDescriptor source = null;
- ParcelFileDescriptor sink = null;
- try {
- ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
- source = pipe[0];
- sink = pipe[1];
-
- in = new FileInputStream(source.getFileDescriptor());
- out = new FileOutputStream(mFile);
-
- // Async call to initiate the other process writing the data.
- mRemoteInterface.write(pages, sink, callback, sequence);
-
- // Close the source. It is now held by the client.
- sink.close();
- sink = null;
-
- // Read the data.
- final byte[] buffer = new byte[8192];
- while (true) {
- final int readByteCount = in.read(buffer);
- if (readByteCount < 0) {
- break;
- }
- out.write(buffer, 0, readByteCount);
- }
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling write()", re);
- } catch (IOException ioe) {
- Log.e(LOG_TAG, "Error calling write()", ioe);
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
- IoUtils.closeQuietly(sink);
- IoUtils.closeQuietly(source);
- }
- return null;
- }
- }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
- }
-
- public void finish() {
- if (DEBUG) {
- Log.i(LOG_TAG, "finish()");
- }
- try {
- mRemoteInterface.finish();
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling finish()", re);
- }
- }
-
- public void cancel() {
- if (DEBUG) {
- Log.i(LOG_TAG, "cancel()");
- }
- try {
- mRemoteInterface.cancel();
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error calling cancel()", re);
- }
- }
-}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterActivity.java
deleted file mode 100644
index 141dbd1..0000000
--- a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterActivity.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.printspooler;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.print.PrinterId;
-
-import com.android.printspooler.SelectPrinterFragment.OnPrinterSelectedListener;
-
-public class SelectPrinterActivity extends Activity implements OnPrinterSelectedListener {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.select_printer_activity);
- }
-
- @Override
- public void onPrinterSelected(PrinterId printer) {
- Intent intent = new Intent();
- intent.putExtra(PrintJobConfigActivity.INTENT_EXTRA_PRINTER_ID, printer);
- setResult(RESULT_OK, intent);
- finish();
- }
-}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
similarity index 99%
rename from packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
rename to packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
index 968a8bf..929f0fc 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.printspooler;
+package com.android.printspooler.model;
import android.app.Notification;
import android.app.Notification.InboxStyle;
@@ -38,6 +38,8 @@
import android.provider.Settings;
import android.util.Log;
+import com.android.printspooler.R;
+
import java.util.ArrayList;
import java.util.List;
@@ -45,7 +47,7 @@
* This class is responsible for updating the print notifications
* based on print job state transitions.
*/
-public class NotificationController {
+final class NotificationController {
public static final boolean DEBUG = false;
public static final String LOG_TAG = "NotificationController";
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerProvider.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerProvider.java
new file mode 100644
index 0000000..06723c3
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerProvider.java
@@ -0,0 +1,60 @@
+/*
+ * 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.printspooler.model;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+
+public class PrintSpoolerProvider implements ServiceConnection {
+ private final Context mContext;
+ private final Runnable mCallback;
+
+ private PrintSpoolerService mSpooler;
+
+ public PrintSpoolerProvider(Context context, Runnable callback) {
+ mContext = context;
+ mCallback = callback;
+ Intent intent = new Intent(mContext, PrintSpoolerService.class);
+ mContext.bindService(intent, this, 0);
+ }
+
+ public PrintSpoolerService getSpooler() {
+ return mSpooler;
+ }
+
+ public void destroy() {
+ if (mSpooler != null) {
+ mContext.unbindService(this);
+ }
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mSpooler = ((PrintSpoolerService.PrintSpooler) service).getService();
+ if (mSpooler != null) {
+ mCallback.run();
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ /* do nothing - we are in the same process */
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
similarity index 95%
rename from packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
rename to packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
index 615d667..045a2f9 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package com.android.printspooler;
+package com.android.printspooler.model;
import android.app.Service;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -38,7 +39,6 @@
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrinterId;
-import android.print.PrinterInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AtomicFile;
@@ -48,6 +48,7 @@
import com.android.internal.os.HandlerCaller;
import com.android.internal.util.FastXmlSerializer;
+import com.android.printspooler.R;
import libcore.io.IoUtils;
@@ -89,7 +90,7 @@
private final Object mLock = new Object();
- private final List<PrintJobInfo> mPrintJobs = new ArrayList<PrintJobInfo>();
+ private final List<PrintJobInfo> mPrintJobs = new ArrayList<>();
private static PrintSpoolerService sInstance;
@@ -274,7 +275,7 @@
&& isScheduledState(printJob.getState()));
if (sameComponent && sameAppId && sameState) {
if (foundPrintJobs == null) {
- foundPrintJobs = new ArrayList<PrintJobInfo>();
+ foundPrintJobs = new ArrayList<>();
}
foundPrintJobs.add(printJob);
}
@@ -400,7 +401,7 @@
FileOutputStream out = null;
try {
if (printJob != null) {
- File file = generateFileForPrintJob(printJobId);
+ File file = generateFileForPrintJob(PrintSpoolerService.this, printJobId);
in = new FileInputStream(file);
out = new FileOutputStream(fd.getFileDescriptor());
}
@@ -427,8 +428,8 @@
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
}
- public File generateFileForPrintJob(PrintJobId printJobId) {
- return new File(getFilesDir(), PRINT_JOB_FILE_PREFIX
+ public static File generateFileForPrintJob(Context context, PrintJobId printJobId) {
+ return new File(context.getFilesDir(), PRINT_JOB_FILE_PREFIX
+ printJobId.flattenToString() + "." + PRINT_FILE_EXTENSION);
}
@@ -461,7 +462,7 @@
}
private void removePrintJobFileLocked(PrintJobId printJobId) {
- File file = generateFileForPrintJob(printJobId);
+ File file = generateFileForPrintJob(PrintSpoolerService.this, printJobId);
if (file.exists()) {
file.delete();
if (DEBUG_PRINT_JOB_LIFECYCLE) {
@@ -557,7 +558,7 @@
}
private boolean isObsoleteState(int printJobState) {
- return (isTeminalState(printJobState)
+ return (isTerminalState(printJobState)
|| printJobState == PrintJobInfo.STATE_QUEUED);
}
@@ -574,7 +575,7 @@
|| printJobState == PrintJobInfo.STATE_BLOCKED;
}
- private boolean isTeminalState(int printJobState) {
+ private boolean isTerminalState(int printJobState) {
return printJobState == PrintJobInfo.STATE_COMPLETED
|| printJobState == PrintJobInfo.STATE_CANCELED;
}
@@ -619,61 +620,23 @@
}
}
- public void setPrintJobCopiesNoPersistence(PrintJobId printJobId, int copies) {
+ public void updatePrintJobUserConfigurableOptionsNoPersistence(PrintJobInfo printJob) {
synchronized (mLock) {
- PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
- if (printJob != null) {
- printJob.setCopies(copies);
+ final int printJobCount = mPrintJobs.size();
+ for (int i = 0; i < printJobCount; i++) {
+ PrintJobInfo cachedPrintJob = mPrintJobs.get(i);
+ if (cachedPrintJob.getId().equals(printJob.getId())) {
+ cachedPrintJob.setPrinterId(printJob.getPrinterId());
+ cachedPrintJob.setPrinterName(printJob.getPrinterName());
+ cachedPrintJob.setCopies(printJob.getCopies());
+ cachedPrintJob.setDocumentInfo(printJob.getDocumentInfo());
+ cachedPrintJob.setPages(printJob.getPages());
+ cachedPrintJob.setAttributes(printJob.getAttributes());
+ cachedPrintJob.setAdvancedOptions(printJob.getAdvancedOptions());
+ return;
+ }
}
- }
- }
-
- public void setPrintJobAdvancedOptionsNoPersistence(PrintJobId printJobId,
- Bundle advancedOptions) {
- synchronized (mLock) {
- PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
- if (printJob != null) {
- printJob.setAdvancedOptions(advancedOptions);
- }
- }
- }
-
- public void setPrintJobPrintDocumentInfoNoPersistence(PrintJobId printJobId,
- PrintDocumentInfo info) {
- synchronized (mLock) {
- PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
- if (printJob != null) {
- printJob.setDocumentInfo(info);
- }
- }
- }
-
- public void setPrintJobAttributesNoPersistence(PrintJobId printJobId,
- PrintAttributes attributes) {
- synchronized (mLock) {
- PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
- if (printJob != null) {
- printJob.setAttributes(attributes);
- }
- }
- }
-
- public void setPrintJobPrinterNoPersistence(PrintJobId printJobId, PrinterInfo printer) {
- synchronized (mLock) {
- PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
- if (printJob != null) {
- printJob.setPrinterId(printer.getId());
- printJob.setPrinterName(printer.getName());
- }
- }
- }
-
- public void setPrintJobPagesNoPersistence(PrintJobId printJobId, PageRange[] pages) {
- synchronized (mLock) {
- PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
- if (printJob != null) {
- printJob.setPages(pages);
- }
+ throw new IllegalArgumentException("No print job with id:" + printJob.getId());
}
}
@@ -1250,7 +1213,7 @@
}
}
- final class PrintSpooler extends IPrintSpooler.Stub {
+ public final class PrintSpooler extends IPrintSpooler.Stub {
@Override
public void getPrintJobInfos(IPrintSpoolerCallbacks callback,
ComponentName componentName, int state, int appId, int sequence)
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
new file mode 100644
index 0000000..e70c361
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -0,0 +1,1148 @@
+/*
+ * 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.printspooler.model;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder.DeathRecipient;
+import android.os.ICancellationSignal;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.print.ILayoutResultCallback;
+import android.print.IPrintDocumentAdapter;
+import android.print.IPrintDocumentAdapterObserver;
+import android.print.IWriteResultCallback;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintDocumentInfo;
+import android.util.Log;
+
+import com.android.printspooler.R;
+import com.android.printspooler.util.PageRangeUtils;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+
+public final class RemotePrintDocument {
+ private static final String LOG_TAG = "RemotePrintDocument";
+
+ private static final boolean DEBUG = false;
+
+ private static final int STATE_INITIAL = 0;
+ private static final int STATE_STARTED = 1;
+ private static final int STATE_UPDATING = 2;
+ private static final int STATE_UPDATED = 3;
+ private static final int STATE_FAILED = 4;
+ private static final int STATE_FINISHED = 5;
+ private static final int STATE_CANCELING = 6;
+ private static final int STATE_CANCELED = 7;
+ private static final int STATE_DESTROYED = 8;
+
+ private static final PageRange[] ALL_PAGES_ARRAY = new PageRange[] {
+ PageRange.ALL_PAGES
+ };
+
+ private final Context mContext;
+
+ private final RemotePrintDocumentInfo mDocumentInfo;
+ private final UpdateSpec mUpdateSpec = new UpdateSpec();
+
+ private final Looper mLooper;
+ private final IPrintDocumentAdapter mPrintDocumentAdapter;
+ private final DocumentObserver mDocumentObserver;
+
+ private final UpdateResultCallbacks mUpdateCallbacks;
+
+ private final CommandDoneCallback mCommandResultCallback =
+ new CommandDoneCallback() {
+ @Override
+ public void onDone() {
+ if (mCurrentCommand.isCompleted()) {
+ if (mCurrentCommand instanceof LayoutCommand) {
+ // If there is a next command after a layout is done, then another
+ // update was issued and the next command is another layout, so we
+ // do nothing. However, if there is no next command we may need to
+ // ask for some pages given we do not already have them or we do
+ // but the content has changed.
+ LayoutCommand layoutCommand = (LayoutCommand) mCurrentCommand;
+ if (mNextCommand == null) {
+ if (layoutCommand.isDocumentChanged() || !PageRangeUtils.contains(
+ mDocumentInfo.writtenPages, mUpdateSpec.pages)) {
+ mNextCommand = new WriteCommand(mContext, mLooper,
+ mPrintDocumentAdapter, mDocumentInfo,
+ mDocumentInfo.info.getPageCount(), mUpdateSpec.pages,
+ mDocumentInfo.file, mCommandResultCallback);
+ } else {
+ // If we have the requested pages just update that ones to be printed.
+ mDocumentInfo.printedPages = computePrintedPages(mUpdateSpec.pages,
+ mDocumentInfo.writtenPages, mDocumentInfo.info.getPageCount());
+ // Notify we are done.
+ notifyUpdateCompleted();
+ }
+ }
+ } else {
+ // We always notify after a write.
+ notifyUpdateCompleted();
+ }
+ runPendingCommand();
+ } else if (mCurrentCommand.isFailed()) {
+ mState = STATE_FAILED;
+ CharSequence error = mCurrentCommand.getError();
+ mCurrentCommand = null;
+ mNextCommand = null;
+ mUpdateSpec.reset();
+ notifyUpdateFailed(error);
+ } else if (mCurrentCommand.isCanceled()) {
+ if (mState == STATE_CANCELING) {
+ mState = STATE_CANCELED;
+ notifyUpdateCanceled();
+ }
+ runPendingCommand();
+ }
+ }
+ };
+
+ private final DeathRecipient mDeathRecipient = new DeathRecipient() {
+ @Override
+ public void binderDied() {
+ finish();
+ }
+ };
+
+ private int mState = STATE_INITIAL;
+
+ private AsyncCommand mCurrentCommand;
+ private AsyncCommand mNextCommand;
+
+ public interface DocumentObserver {
+ public void onDestroy();
+ }
+
+ public interface UpdateResultCallbacks {
+ public void onUpdateCompleted(RemotePrintDocumentInfo document);
+ public void onUpdateCanceled();
+ public void onUpdateFailed(CharSequence error);
+ }
+
+ public RemotePrintDocument(Context context, IPrintDocumentAdapter adapter,
+ File file, DocumentObserver destroyListener, UpdateResultCallbacks callbacks) {
+ mPrintDocumentAdapter = adapter;
+ mLooper = context.getMainLooper();
+ mContext = context;
+ mDocumentObserver = destroyListener;
+ mDocumentInfo = new RemotePrintDocumentInfo();
+ mDocumentInfo.file = file;
+ mUpdateCallbacks = callbacks;
+ connectToRemoteDocument();
+ }
+
+ public void start() {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLED] start()");
+ }
+ if (mState != STATE_INITIAL) {
+ throw new IllegalStateException("Cannot start in state:" + stateToString(mState));
+ }
+ try {
+ mPrintDocumentAdapter.start();
+ mState = STATE_STARTED;
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling start()", re);
+ mState = STATE_FAILED;
+ mDocumentObserver.onDestroy();
+ }
+ }
+
+ public boolean update(PrintAttributes attributes, PageRange[] pages, boolean preview) {
+ boolean willUpdate;
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLED] update()");
+ }
+
+ if (hasUpdateError()) {
+ throw new IllegalStateException("Cannot update without a clearing the failure");
+ }
+
+ if (mState == STATE_INITIAL || mState == STATE_FINISHED || mState == STATE_DESTROYED) {
+ throw new IllegalStateException("Cannot update in state:" + stateToString(mState));
+ }
+
+ // We schedule a layout if the constraints changed.
+ if (!mUpdateSpec.hasSameConstraints(attributes, preview)) {
+ willUpdate = true;
+
+ // If there is a current command that is running we ask for a
+ // cancellation and start over.
+ if (mCurrentCommand != null && (mCurrentCommand.isRunning()
+ || mCurrentCommand.isPending())) {
+ mCurrentCommand.cancel();
+ }
+
+ // Schedule a layout command.
+ PrintAttributes oldAttributes = mDocumentInfo.attributes != null
+ ? mDocumentInfo.attributes : new PrintAttributes.Builder().build();
+ AsyncCommand command = new LayoutCommand(mLooper, mPrintDocumentAdapter,
+ mDocumentInfo, oldAttributes, attributes, preview, mCommandResultCallback);
+ scheduleCommand(command);
+
+ mState = STATE_UPDATING;
+ // If no layout in progress and we don't have all pages - schedule a write.
+ } else if ((!(mCurrentCommand instanceof LayoutCommand)
+ || (!mCurrentCommand.isPending() && !mCurrentCommand.isRunning()))
+ && !PageRangeUtils.contains(mUpdateSpec.pages, pages)) {
+ willUpdate = true;
+
+ // Cancel the current write as a new one is to be scheduled.
+ if (mCurrentCommand instanceof WriteCommand
+ && (mCurrentCommand.isPending() || mCurrentCommand.isRunning())) {
+ mCurrentCommand.cancel();
+ }
+
+ // Schedule a write command.
+ AsyncCommand command = new WriteCommand(mContext, mLooper, mPrintDocumentAdapter,
+ mDocumentInfo, mDocumentInfo.info.getPageCount(), pages,
+ mDocumentInfo.file, mCommandResultCallback);
+ scheduleCommand(command);
+
+ mState = STATE_UPDATING;
+ } else {
+ willUpdate = false;
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[SKIPPING] No update needed");
+ }
+ }
+
+ // Keep track of what is requested.
+ mUpdateSpec.update(attributes, preview, pages);
+
+ runPendingCommand();
+
+ return willUpdate;
+ }
+
+ public void finish() {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLED] finish()");
+ }
+ if (mState != STATE_STARTED && mState != STATE_UPDATED
+ && mState != STATE_FAILED && mState != STATE_CANCELING) {
+ throw new IllegalStateException("Cannot finish in state:"
+ + stateToString(mState));
+ }
+ try {
+ mPrintDocumentAdapter.finish();
+ mState = STATE_FINISHED;
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling finish()", re);
+ mState = STATE_FAILED;
+ mDocumentObserver.onDestroy();
+ }
+ }
+
+ public void cancel() {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLED] cancel()");
+ }
+
+ if (mState == STATE_CANCELING) {
+ return;
+ }
+
+ if (mState != STATE_UPDATING) {
+ throw new IllegalStateException("Cannot cancel in state:" + stateToString(mState));
+ }
+
+ mState = STATE_CANCELING;
+
+ mCurrentCommand.cancel();
+ }
+
+ public void destroy() {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLED] destroy()");
+ }
+ if (mState == STATE_DESTROYED) {
+ throw new IllegalStateException("Cannot destroy in state:" + stateToString(mState));
+ }
+
+ mState = STATE_DESTROYED;
+
+ disconnectFromRemoteDocument();
+ mDocumentObserver.onDestroy();
+ }
+
+ public boolean isUpdating() {
+ return mState == STATE_UPDATING || mState == STATE_CANCELING;
+ }
+
+ public boolean isDestroyed() {
+ return mState == STATE_DESTROYED;
+ }
+
+ public boolean hasUpdateError() {
+ return mState == STATE_FAILED;
+ }
+
+ public void clearUpdateError() {
+ if (!hasUpdateError()) {
+ throw new IllegalStateException("No update error to clear");
+ }
+ mState = STATE_STARTED;
+ }
+
+ public RemotePrintDocumentInfo getDocumentInfo() {
+ return mDocumentInfo;
+ }
+
+ public void writeContent(ContentResolver contentResolver, Uri uri) {
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ in = new FileInputStream(mDocumentInfo.file);
+ out = contentResolver.openOutputStream(uri);
+ final byte[] buffer = new byte[8192];
+ while (true) {
+ final int readByteCount = in.read(buffer);
+ if (readByteCount < 0) {
+ break;
+ }
+ out.write(buffer, 0, readByteCount);
+ }
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Error writing document content.", e);
+ } finally {
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(out);
+ }
+ }
+
+ private void notifyUpdateCanceled() {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLING] onUpdateCanceled()");
+ }
+ mUpdateCallbacks.onUpdateCanceled();
+ }
+
+ private void notifyUpdateCompleted() {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLING] onUpdateCompleted()");
+ }
+ mUpdateCallbacks.onUpdateCompleted(mDocumentInfo);
+ }
+
+ private void notifyUpdateFailed(CharSequence error) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLING] onUpdateCompleted()");
+ }
+ mUpdateCallbacks.onUpdateFailed(error);
+ }
+
+ private void connectToRemoteDocument() {
+ try {
+ mPrintDocumentAdapter.asBinder().linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "The printing process is dead.");
+ destroy();
+ return;
+ }
+
+ try {
+ mPrintDocumentAdapter.setObserver(new PrintDocumentAdapterObserver(this));
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Error setting observer to the print adapter.");
+ destroy();
+ }
+ }
+
+ private void disconnectFromRemoteDocument() {
+ try {
+ mPrintDocumentAdapter.setObserver(null);
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Error setting observer to the print adapter.");
+ // Keep going - best effort...
+ }
+
+ mPrintDocumentAdapter.asBinder().unlinkToDeath(mDeathRecipient, 0);
+ }
+
+ private void scheduleCommand(AsyncCommand command) {
+ if (mCurrentCommand == null) {
+ mCurrentCommand = command;
+ } else {
+ mNextCommand = command;
+ }
+ }
+
+ private void runPendingCommand() {
+ if (mCurrentCommand != null
+ && (mCurrentCommand.isCompleted()
+ || mCurrentCommand.isCanceled())) {
+ mCurrentCommand = mNextCommand;
+ mNextCommand = null;
+ }
+
+ if (mCurrentCommand != null) {
+ if (mCurrentCommand.isPending()) {
+ mCurrentCommand.run();
+ }
+ mState = STATE_UPDATING;
+ } else {
+ mState = STATE_UPDATED;
+ }
+ }
+
+ private static String stateToString(int state) {
+ switch (state) {
+ case STATE_FINISHED: {
+ return "STATE_FINISHED";
+ }
+ case STATE_FAILED: {
+ return "STATE_FAILED";
+ }
+ case STATE_STARTED: {
+ return "STATE_STARTED";
+ }
+ case STATE_UPDATING: {
+ return "STATE_UPDATING";
+ }
+ case STATE_UPDATED: {
+ return "STATE_UPDATED";
+ }
+ case STATE_CANCELING: {
+ return "STATE_CANCELING";
+ }
+ case STATE_CANCELED: {
+ return "STATE_CANCELED";
+ }
+ case STATE_DESTROYED: {
+ return "STATE_DESTROYED";
+ }
+ default: {
+ return "STATE_UNKNOWN";
+ }
+ }
+ }
+
+ private static PageRange[] computePrintedPages(PageRange[] requestedPages,
+ PageRange[] writtenPages, int pageCount) {
+ // Adjust the print job pages based on what was requested and written.
+ // The cases are ordered in the most expected to the least expected.
+ if (Arrays.equals(writtenPages, requestedPages)) {
+ // We got a document with exactly the pages we wanted. Hence,
+ // the printer has to print all pages in the data.
+ return ALL_PAGES_ARRAY;
+ } else if (Arrays.equals(writtenPages, ALL_PAGES_ARRAY)) {
+ // We requested specific pages but got all of them. Hence,
+ // the printer has to print only the requested pages.
+ return requestedPages;
+ } else if (PageRangeUtils.contains(writtenPages, requestedPages)) {
+ // We requested specific pages and got more but not all pages.
+ // Hence, we have to offset appropriately the printed pages to
+ // be based off the start of the written ones instead of zero.
+ // The written pages are always non-null and not empty.
+ final int offset = -writtenPages[0].getStart();
+ PageRangeUtils.offset(requestedPages, offset);
+ return requestedPages;
+ } else if (Arrays.equals(requestedPages, ALL_PAGES_ARRAY)
+ && isAllPages(writtenPages, pageCount)) {
+ // We requested all pages via the special constant and got all
+ // of them as an explicit enumeration. Hence, the printer has
+ // to print only the requested pages.
+ return ALL_PAGES_ARRAY;
+ }
+
+ return null;
+ }
+
+ private static boolean isAllPages(PageRange[] pageRanges, int pageCount) {
+ return pageRanges.length > 0 && pageRanges[0].getStart() == 0
+ && pageRanges[pageRanges.length - 1].getEnd() == pageCount - 1;
+ }
+
+ static final class UpdateSpec {
+ final PrintAttributes attributes = new PrintAttributes.Builder().build();
+ boolean preview;
+ PageRange[] pages;
+
+ public void update(PrintAttributes attributes, boolean preview,
+ PageRange[] pages) {
+ this.attributes.copyFrom(attributes);
+ this.preview = preview;
+ this.pages = Arrays.copyOf(pages, pages.length);
+ }
+
+ public void reset() {
+ attributes.clear();
+ preview = false;
+ pages = null;
+ }
+
+ public boolean hasSameConstraints(PrintAttributes attributes, boolean preview) {
+ return this.attributes.equals(attributes) && this.preview == preview;
+ }
+ }
+
+ public static final class RemotePrintDocumentInfo {
+ public PrintAttributes attributes;
+ public Bundle metadata;
+ public PrintDocumentInfo info;
+ public PageRange[] printedPages;
+ public PageRange[] writtenPages;
+ public File file;
+ }
+
+ private interface CommandDoneCallback {
+ public void onDone();
+ }
+
+ private static abstract class AsyncCommand implements Runnable {
+ private static final int STATE_PENDING = 0;
+ private static final int STATE_RUNNING = 1;
+ private static final int STATE_COMPLETED = 2;
+ private static final int STATE_CANCELED = 3;
+ private static final int STATE_CANCELING = 4;
+ private static final int STATE_FAILED = 5;
+
+ private static int sSequenceCounter;
+
+ protected final int mSequence = sSequenceCounter++;
+ protected final IPrintDocumentAdapter mAdapter;
+ protected final RemotePrintDocumentInfo mDocument;
+
+ protected final CommandDoneCallback mDoneCallback;
+
+ protected ICancellationSignal mCancellation;
+
+ private CharSequence mError;
+
+ private int mState = STATE_PENDING;
+
+ public AsyncCommand(IPrintDocumentAdapter adapter, RemotePrintDocumentInfo document,
+ CommandDoneCallback doneCallback) {
+ mAdapter = adapter;
+ mDocument = document;
+ mDoneCallback = doneCallback;
+ }
+
+ protected final boolean isCanceling() {
+ return mState == STATE_CANCELING;
+ }
+
+ public final boolean isCanceled() {
+ return mState == STATE_CANCELED;
+ }
+
+ public final void cancel() {
+ if (isRunning()) {
+ canceling();
+ if (mCancellation != null) {
+ try {
+ mCancellation.cancel();
+ } catch (RemoteException re) {
+ Log.w(LOG_TAG, "Error while canceling", re);
+ }
+ }
+ } else {
+ canceled();
+
+ // Done.
+ mDoneCallback.onDone();
+ }
+ }
+
+ protected final void canceling() {
+ if (mState != STATE_PENDING && mState != STATE_RUNNING) {
+ throw new IllegalStateException("Command not pending or running.");
+ }
+ mState = STATE_CANCELING;
+ }
+
+ protected final void canceled() {
+ if (mState != STATE_CANCELING) {
+ throw new IllegalStateException("Not canceling.");
+ }
+ mState = STATE_CANCELED;
+ }
+
+ public final boolean isPending() {
+ return mState == STATE_PENDING;
+ }
+
+ protected final void running() {
+ if (mState != STATE_PENDING) {
+ throw new IllegalStateException("Not pending.");
+ }
+ mState = STATE_RUNNING;
+ }
+
+ public final boolean isRunning() {
+ return mState == STATE_RUNNING;
+ }
+
+ protected final void completed() {
+ if (mState != STATE_RUNNING && mState != STATE_CANCELING) {
+ throw new IllegalStateException("Not running.");
+ }
+ mState = STATE_COMPLETED;
+ }
+
+ public final boolean isCompleted() {
+ return mState == STATE_COMPLETED;
+ }
+
+ protected final void failed(CharSequence error) {
+ if (mState != STATE_RUNNING) {
+ throw new IllegalStateException("Not running.");
+ }
+ mState = STATE_FAILED;
+
+ mError = error;
+ }
+
+ public final boolean isFailed() {
+ return mState == STATE_FAILED;
+ }
+
+ public CharSequence getError() {
+ return mError;
+ }
+ }
+
+ private static final class LayoutCommand extends AsyncCommand {
+ private final PrintAttributes mOldAttributes = new PrintAttributes.Builder().build();
+ private final PrintAttributes mNewAttributes = new PrintAttributes.Builder().build();
+ private final Bundle mMetadata = new Bundle();
+
+ private final ILayoutResultCallback mRemoteResultCallback;
+
+ private final Handler mHandler;
+
+ private boolean mDocumentChanged;
+
+ public LayoutCommand(Looper looper, IPrintDocumentAdapter adapter,
+ RemotePrintDocumentInfo document, PrintAttributes oldAttributes,
+ PrintAttributes newAttributes, boolean preview, CommandDoneCallback callback) {
+ super(adapter, document, callback);
+ mHandler = new LayoutHandler(looper);
+ mRemoteResultCallback = new LayoutResultCallback(mHandler);
+ mOldAttributes.copyFrom(oldAttributes);
+ mNewAttributes.copyFrom(newAttributes);
+ mMetadata.putBoolean(PrintDocumentAdapter.EXTRA_PRINT_PREVIEW, preview);
+ }
+
+ public boolean isDocumentChanged() {
+ return mDocumentChanged;
+ }
+
+ @Override
+ public void run() {
+ running();
+
+ try {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[PERFORMING] layout");
+ }
+ mAdapter.layout(mOldAttributes, mNewAttributes, mRemoteResultCallback,
+ mMetadata, mSequence);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error calling layout", re);
+ handleOnLayoutFailed(null, mSequence);
+ }
+ }
+
+ private void handleOnLayoutStarted(ICancellationSignal cancellation, int sequence) {
+ if (sequence != mSequence) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLBACK] onLayoutStarted");
+ }
+
+ if (isCanceling()) {
+ try {
+ cancellation.cancel();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error cancelling", re);
+ handleOnLayoutFailed(null, mSequence);
+ }
+ } else {
+ mCancellation = cancellation;
+ }
+ }
+
+ private void handleOnLayoutFinished(PrintDocumentInfo info,
+ boolean changed, int sequence) {
+ if (sequence != mSequence) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLBACK] onLayoutFinished");
+ }
+
+ completed();
+
+ // If the document description changed or the content in the
+ // document changed, the we need to invalidate the pages.
+ if (changed || !equalsIgnoreSize(mDocument.info, info)) {
+ // If the content changed we throw away all pages as
+ // we will request them again with the new content.
+ mDocument.writtenPages = null;
+ mDocument.printedPages = null;
+ mDocumentChanged = true;
+ }
+
+ // Update the document with data from the layout pass.
+ mDocument.attributes = mNewAttributes;
+ mDocument.metadata = mMetadata;
+ mDocument.info = info;
+
+ // Release the remote cancellation interface.
+ mCancellation = null;
+
+ // Done.
+ mDoneCallback.onDone();
+ }
+
+ private void handleOnLayoutFailed(CharSequence error, int sequence) {
+ if (sequence != mSequence) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLBACK] onLayoutFailed");
+ }
+
+ failed(error);
+
+ // Release the remote cancellation interface.
+ mCancellation = null;
+
+ // Failed.
+ mDoneCallback.onDone();
+ }
+
+ private void handleOnLayoutCanceled(int sequence) {
+ if (sequence != mSequence) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLBACK] onLayoutCanceled");
+ }
+
+ canceled();
+
+ // Release the remote cancellation interface.
+ mCancellation = null;
+
+ // Done.
+ mDoneCallback.onDone();
+ }
+
+ private boolean equalsIgnoreSize(PrintDocumentInfo lhs, PrintDocumentInfo rhs) {
+ if (lhs == rhs) {
+ return true;
+ }
+ if (lhs == null) {
+ return false;
+ } else {
+ if (rhs == null) {
+ return false;
+ }
+ if (lhs.getContentType() != rhs.getContentType()
+ || lhs.getPageCount() != rhs.getPageCount()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private final class LayoutHandler extends Handler {
+ public static final int MSG_ON_LAYOUT_STARTED = 1;
+ public static final int MSG_ON_LAYOUT_FINISHED = 2;
+ public static final int MSG_ON_LAYOUT_FAILED = 3;
+ public static final int MSG_ON_LAYOUT_CANCELED = 4;
+
+ public LayoutHandler(Looper looper) {
+ super(looper, null, false);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_ON_LAYOUT_STARTED: {
+ ICancellationSignal cancellation = (ICancellationSignal) message.obj;
+ final int sequence = message.arg1;
+ handleOnLayoutStarted(cancellation, sequence);
+ } break;
+
+ case MSG_ON_LAYOUT_FINISHED: {
+ PrintDocumentInfo info = (PrintDocumentInfo) message.obj;
+ final boolean changed = (message.arg1 == 1);
+ final int sequence = message.arg2;
+ handleOnLayoutFinished(info, changed, sequence);
+ } break;
+
+ case MSG_ON_LAYOUT_FAILED: {
+ CharSequence error = (CharSequence) message.obj;
+ final int sequence = message.arg1;
+ handleOnLayoutFailed(error, sequence);
+ } break;
+
+ case MSG_ON_LAYOUT_CANCELED: {
+ final int sequence = message.arg1;
+ handleOnLayoutCanceled(sequence);
+ } break;
+ }
+ }
+ }
+
+ private static final class LayoutResultCallback extends ILayoutResultCallback.Stub {
+ private final WeakReference<Handler> mWeakHandler;
+
+ public LayoutResultCallback(Handler handler) {
+ mWeakHandler = new WeakReference<>(handler);
+ }
+
+ @Override
+ public void onLayoutStarted(ICancellationSignal cancellation, int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(LayoutHandler.MSG_ON_LAYOUT_STARTED,
+ sequence, 0, cancellation).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onLayoutFinished(PrintDocumentInfo info, boolean changed, int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(LayoutHandler.MSG_ON_LAYOUT_FINISHED,
+ changed ? 1 : 0, sequence, info).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onLayoutFailed(CharSequence error, int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(LayoutHandler.MSG_ON_LAYOUT_FAILED,
+ sequence, 0, error).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onLayoutCanceled(int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(LayoutHandler.MSG_ON_LAYOUT_CANCELED,
+ sequence, 0).sendToTarget();
+ }
+ }
+ }
+ }
+
+ private static final class WriteCommand extends AsyncCommand {
+ private final int mPageCount;
+ private final PageRange[] mPages;
+ private final File mContentFile;
+
+ private final IWriteResultCallback mRemoteResultCallback;
+ private final CommandDoneCallback mDoneCallback;
+
+ private final Context mContext;
+ private final Handler mHandler;
+
+ public WriteCommand(Context context, Looper looper, IPrintDocumentAdapter adapter,
+ RemotePrintDocumentInfo document, int pageCount, PageRange[] pages,
+ File contentFile, CommandDoneCallback callback) {
+ super(adapter, document, callback);
+ mContext = context;
+ mHandler = new WriteHandler(looper);
+ mRemoteResultCallback = new WriteResultCallback(mHandler);
+ mPageCount = pageCount;
+ mPages = Arrays.copyOf(pages, pages.length);
+ mContentFile = contentFile;
+ mDoneCallback = callback;
+ }
+
+ @Override
+ public void run() {
+ running();
+
+ // This is a long running operation as we will be reading fully
+ // the written data. In case of a cancellation, we ask the client
+ // to stop writing data and close the file descriptor after
+ // which we will reach the end of the stream, thus stop reading.
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ InputStream in = null;
+ OutputStream out = null;
+ ParcelFileDescriptor source = null;
+ ParcelFileDescriptor sink = null;
+ try {
+ ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
+ source = pipe[0];
+ sink = pipe[1];
+
+ in = new FileInputStream(source.getFileDescriptor());
+ out = new FileOutputStream(mContentFile);
+
+ // Async call to initiate the other process writing the data.
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[PERFORMING] write");
+ }
+ mAdapter.write(mPages, sink, mRemoteResultCallback, mSequence);
+
+ // Close the source. It is now held by the client.
+ sink.close();
+ sink = null;
+
+ // Read the data.
+ final byte[] buffer = new byte[8192];
+ while (true) {
+ final int readByteCount = in.read(buffer);
+ if (readByteCount < 0) {
+ break;
+ }
+ out.write(buffer, 0, readByteCount);
+ }
+ } catch (RemoteException | IOException e) {
+ Log.e(LOG_TAG, "Error calling write()", e);
+ } finally {
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(out);
+ IoUtils.closeQuietly(sink);
+ IoUtils.closeQuietly(source);
+ }
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ }
+
+ private void handleOnWriteStarted(ICancellationSignal cancellation, int sequence) {
+ if (sequence != mSequence) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLBACK] onWriteStarted");
+ }
+
+ if (isCanceling()) {
+ try {
+ cancellation.cancel();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error cancelling", re);
+ handleOnWriteFailed(null, sequence);
+ }
+ } else {
+ mCancellation = cancellation;
+ }
+ }
+
+ private void handleOnWriteFinished(PageRange[] pages, int sequence) {
+ if (sequence != mSequence) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLBACK] onWriteFinished");
+ }
+
+ PageRange[] writtenPages = PageRangeUtils.normalize(pages);
+ PageRange[] printedPages = computePrintedPages(mPages, writtenPages, mPageCount);
+
+ // Handle if we got invalid pages
+ if (printedPages != null) {
+ mDocument.writtenPages = writtenPages;
+ mDocument.printedPages = printedPages;
+ completed();
+ } else {
+ mDocument.writtenPages = null;
+ mDocument.printedPages = null;
+ failed(mContext.getString(R.string.print_error_default_message));
+ }
+
+ // Release the remote cancellation interface.
+ mCancellation = null;
+
+ // Done.
+ mDoneCallback.onDone();
+ }
+
+ private void handleOnWriteFailed(CharSequence error, int sequence) {
+ if (sequence != mSequence) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLBACK] onWriteFailed");
+ }
+
+ failed(error);
+
+ // Release the remote cancellation interface.
+ mCancellation = null;
+
+ // Done.
+ mDoneCallback.onDone();
+ }
+
+ private void handleOnWriteCanceled(int sequence) {
+ if (sequence != mSequence) {
+ return;
+ }
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[CALLBACK] onWriteCanceled");
+ }
+
+ canceled();
+
+ // Release the remote cancellation interface.
+ mCancellation = null;
+
+ // Done.
+ mDoneCallback.onDone();
+ }
+
+ private final class WriteHandler extends Handler {
+ public static final int MSG_ON_WRITE_STARTED = 1;
+ public static final int MSG_ON_WRITE_FINISHED = 2;
+ public static final int MSG_ON_WRITE_FAILED = 3;
+ public static final int MSG_ON_WRITE_CANCELED = 4;
+
+ public WriteHandler(Looper looper) {
+ super(looper, null, false);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_ON_WRITE_STARTED: {
+ ICancellationSignal cancellation = (ICancellationSignal) message.obj;
+ final int sequence = message.arg1;
+ handleOnWriteStarted(cancellation, sequence);
+ } break;
+
+ case MSG_ON_WRITE_FINISHED: {
+ PageRange[] pages = (PageRange[]) message.obj;
+ final int sequence = message.arg1;
+ handleOnWriteFinished(pages, sequence);
+ } break;
+
+ case MSG_ON_WRITE_FAILED: {
+ CharSequence error = (CharSequence) message.obj;
+ final int sequence = message.arg1;
+ handleOnWriteFailed(error, sequence);
+ } break;
+
+ case MSG_ON_WRITE_CANCELED: {
+ final int sequence = message.arg1;
+ handleOnWriteCanceled(sequence);
+ } break;
+ }
+ }
+ }
+
+ private static final class WriteResultCallback extends IWriteResultCallback.Stub {
+ private final WeakReference<Handler> mWeakHandler;
+
+ public WriteResultCallback(Handler handler) {
+ mWeakHandler = new WeakReference<>(handler);
+ }
+
+ @Override
+ public void onWriteStarted(ICancellationSignal cancellation, int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(WriteHandler.MSG_ON_WRITE_STARTED,
+ sequence, 0, cancellation).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onWriteFinished(PageRange[] pages, int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(WriteHandler.MSG_ON_WRITE_FINISHED,
+ sequence, 0, pages).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onWriteFailed(CharSequence error, int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(WriteHandler.MSG_ON_WRITE_FAILED,
+ sequence, 0, error).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onWriteCanceled(int sequence) {
+ Handler handler = mWeakHandler.get();
+ if (handler != null) {
+ handler.obtainMessage(WriteHandler.MSG_ON_WRITE_CANCELED,
+ sequence, 0).sendToTarget();
+ }
+ }
+ }
+ }
+
+ private static final class PrintDocumentAdapterObserver
+ extends IPrintDocumentAdapterObserver.Stub {
+ private final WeakReference<RemotePrintDocument> mWeakDocument;
+
+ public PrintDocumentAdapterObserver(RemotePrintDocument document) {
+ mWeakDocument = new WeakReference<>(document);
+ }
+
+ @Override
+ public void onDestroy() {
+ final RemotePrintDocument document = mWeakDocument.get();
+ if (document != null) {
+ new Handler(document.mLooper).post(new Runnable() {
+ @Override
+ public void run() {
+ document.mDocumentObserver.onDestroy();
+ }
+ });
+ }
+ }
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
similarity index 98%
rename from packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
rename to packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index 9831839..d802cd8 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.printspooler;
+package com.android.printspooler.ui;
import android.content.ComponentName;
import android.content.Context;
@@ -57,7 +57,7 @@
* This class is responsible for loading printers by doing discovery
* and merging the discovered printers with the previously used ones.
*/
-public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
+public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
private static final String LOG_TAG = "FusedPrintersProvider";
private static final boolean DEBUG = false;
@@ -192,7 +192,7 @@
for (int i = 0; i < favoriteCount; i++) {
printerIds.add(mFavoritePrinters.get(i).getId());
}
- mDiscoverySession.startPrinterDisovery(printerIds);
+ mDiscoverySession.startPrinterDiscovery(printerIds);
List<PrinterInfo> printers = mDiscoverySession.getPrinters();
if (!printers.isEmpty()) {
updatePrinters(printers, mFavoritePrinters);
@@ -281,7 +281,9 @@
mDiscoverySession.stopPrinterStateTracking(mTrackedPrinter);
}
mTrackedPrinter = printerId;
- mDiscoverySession.startPrinterStateTracking(printerId);
+ if (printerId != null) {
+ mDiscoverySession.startPrinterStateTracking(printerId);
+ }
}
}
@@ -514,7 +516,7 @@
}
private List<PrinterInfo> doReadPrinterHistory() {
- FileInputStream in = null;
+ final FileInputStream in;
try {
in = mStatePersistFile.openRead();
} catch (FileNotFoundException fnfe) {
@@ -641,7 +643,7 @@
}
return true;
}
- };
+ }
private final class WriteTask extends AsyncTask<List<PrinterInfo>, Void, Void> {
@Override
@@ -703,6 +705,6 @@
IoUtils.closeQuietly(out);
}
}
- };
+ }
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
new file mode 100644
index 0000000..3e0d7e5
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -0,0 +1,1955 @@
+/*
+ * 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.printspooler.ui;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.database.DataSetObserver;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.print.IPrintDocumentAdapter;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Resolution;
+import android.print.PrintDocumentInfo;
+import android.print.PrintJobInfo;
+import android.print.PrintManager;
+import android.print.PrinterCapabilitiesInfo;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.printservice.PrintService;
+import android.provider.DocumentsContract;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextUtils.SimpleStringSplitter;
+import android.text.TextWatcher;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnFocusChangeListener;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.android.printspooler.R;
+import com.android.printspooler.model.PrintSpoolerProvider;
+import com.android.printspooler.model.PrintSpoolerService;
+import com.android.printspooler.model.RemotePrintDocument;
+import com.android.printspooler.util.MediaSizeUtils;
+import com.android.printspooler.util.MediaSizeUtils.MediaSizeComparator;
+import com.android.printspooler.util.PageRangeUtils;
+import com.android.printspooler.util.PrintOptionUtils;
+import com.android.printspooler.widget.ContentView;
+import com.android.printspooler.widget.ContentView.OptionsStateChangeListener;
+
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PrintActivity extends Activity implements RemotePrintDocument.UpdateResultCallbacks,
+ PrintErrorFragment.OnActionListener, PrintProgressFragment.OnCancelRequestListener {
+ private static final String LOG_TAG = "PrintActivity";
+
+ public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
+
+ private static final int ORIENTATION_PORTRAIT = 0;
+ private static final int ORIENTATION_LANDSCAPE = 1;
+
+ private static final int ACTIVITY_REQUEST_CREATE_FILE = 1;
+ private static final int ACTIVITY_REQUEST_SELECT_PRINTER = 2;
+ private static final int ACTIVITY_REQUEST_POPULATE_ADVANCED_PRINT_OPTIONS = 3;
+
+ private static final int DEST_ADAPTER_MAX_ITEM_COUNT = 9;
+
+ private static final int DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF = Integer.MAX_VALUE;
+ private static final int DEST_ADAPTER_ITEM_ID_ALL_PRINTERS = Integer.MAX_VALUE - 1;
+
+ private static final int STATE_CONFIGURING = 0;
+ private static final int STATE_PRINT_CONFIRMED = 1;
+ private static final int STATE_PRINT_CANCELED = 2;
+ private static final int STATE_UPDATE_FAILED = 3;
+ private static final int STATE_CREATE_FILE_FAILED = 4;
+ private static final int STATE_PRINTER_UNAVAILABLE = 5;
+
+ private static final int UI_STATE_PREVIEW = 0;
+ private static final int UI_STATE_ERROR = 1;
+ private static final int UI_STATE_PROGRESS = 2;
+
+ private static final int MIN_COPIES = 1;
+ private static final String MIN_COPIES_STRING = String.valueOf(MIN_COPIES);
+
+ private static final Pattern PATTERN_DIGITS = Pattern.compile("[\\d]+");
+
+ private static final Pattern PATTERN_ESCAPE_SPECIAL_CHARS = Pattern.compile(
+ "(?=[]\\[+&|!(){}^\"~*?:\\\\])");
+
+ private static final Pattern PATTERN_PAGE_RANGE = Pattern.compile(
+ "[\\s]*[0-9]*[\\s]*[\\-]?[\\s]*[0-9]*[\\s]*?(([,])"
+ + "[\\s]*[0-9]*[\\s]*[\\-]?[\\s]*[0-9]*[\\s]*|[\\s]*)+");
+
+ public static final PageRange[] ALL_PAGES_ARRAY = new PageRange[] {PageRange.ALL_PAGES};
+
+ private final PrinterAvailabilityDetector mPrinterAvailabilityDetector =
+ new PrinterAvailabilityDetector();
+
+ private final SimpleStringSplitter mStringCommaSplitter = new SimpleStringSplitter(',');
+
+ private final OnFocusChangeListener mSelectAllOnFocusListener = new SelectAllOnFocusListener();
+
+ private PrintSpoolerProvider mSpoolerProvider;
+
+ private PrintJobInfo mPrintJob;
+ private RemotePrintDocument mPrintedDocument;
+ private PrinterRegistry mPrinterRegistry;
+
+ private EditText mCopiesEditText;
+
+ private TextView mPageRangeOptionsTitle;
+ private TextView mPageRangeTitle;
+ private EditText mPageRangeEditText;
+
+ private Spinner mDestinationSpinner;
+ private DestinationAdapter mDestinationSpinnerAdapter;
+
+ private Spinner mMediaSizeSpinner;
+ private ArrayAdapter<SpinnerItem<MediaSize>> mMediaSizeSpinnerAdapter;
+
+ private Spinner mColorModeSpinner;
+ private ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter;
+
+ private Spinner mOrientationSpinner;
+ private ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter;
+
+ private Spinner mRangeOptionsSpinner;
+
+ private ContentView mOptionsContent;
+
+ private TextView mSummaryCopies;
+ private TextView mSummaryPaperSize;
+
+ private View mAdvancedPrintOptionsContainer;
+
+ private Button mMoreOptionsButton;
+
+ private ImageView mPrintButton;
+
+ private ProgressMessageController mProgressMessageController;
+
+ private MediaSizeComparator mMediaSizeComparator;
+
+ private PageRange[] mRequestedPages;
+
+ private PrinterInfo mOldCurrentPrinter;
+
+ private String mCallingPackageName;
+
+ private int mState = STATE_CONFIGURING;
+
+ private int mUiState = UI_STATE_PREVIEW;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Bundle extras = getIntent().getExtras();
+
+ mPrintJob = extras.getParcelable(PrintManager.EXTRA_PRINT_JOB);
+ if (mPrintJob == null) {
+ throw new IllegalArgumentException(PrintManager.EXTRA_PRINT_JOB
+ + " cannot be null");
+ }
+ mPrintJob.setAttributes(new PrintAttributes.Builder().build());
+
+ final IBinder adapter = extras.getBinder(PrintManager.EXTRA_PRINT_DOCUMENT_ADAPTER);
+ if (adapter == null) {
+ throw new IllegalArgumentException(PrintManager.EXTRA_PRINT_DOCUMENT_ADAPTER
+ + " cannot be null");
+ }
+
+ mCallingPackageName = extras.getString(DocumentsContract.EXTRA_PACKAGE_NAME);
+
+ // This will take just a few milliseconds, so just wait to
+ // bind to the local service before showing the UI.
+ mSpoolerProvider = new PrintSpoolerProvider(this,
+ new Runnable() {
+ @Override
+ public void run() {
+ // Now that we are bound to the print spooler service,
+ // create the printer registry and wait for it to get
+ // the first batch of results which will be delivered
+ // after reading historical data. This should be pretty
+ // fast, so just wait before showing the UI.
+ mPrinterRegistry = new PrinterRegistry(PrintActivity.this,
+ new Runnable() {
+ @Override
+ public void run() {
+ setTitle(R.string.print_dialog);
+ setContentView(R.layout.print_activity);
+
+ mPrintedDocument = new RemotePrintDocument(PrintActivity.this,
+ IPrintDocumentAdapter.Stub.asInterface(adapter),
+ PrintSpoolerService.generateFileForPrintJob(PrintActivity.this,
+ mPrintJob.getId()),
+ new RemotePrintDocument.DocumentObserver() {
+ @Override
+ public void onDestroy() {
+ finish();
+ }
+ }, PrintActivity.this);
+
+ mProgressMessageController = new ProgressMessageController(PrintActivity.this);
+
+ mMediaSizeComparator = new MediaSizeComparator(PrintActivity.this);
+
+ mDestinationSpinnerAdapter = new DestinationAdapter();
+
+ bindUi();
+
+ updateOptionsUi();
+
+ // Now show the updated UI to avoid flicker.
+ mOptionsContent.setVisibility(View.VISIBLE);
+
+ mRequestedPages = computeRequestedPages();
+
+ mPrintedDocument.start();
+
+ ensurePreviewUiShown();
+ }
+ });
+ }
+ });
+ }
+
+ @Override
+ public void onPause() {
+ if (isFinishing()) {
+ PrintSpoolerService spooler = mSpoolerProvider.getSpooler();
+ if (mState == STATE_PRINT_CONFIRMED) {
+ spooler.updatePrintJobUserConfigurableOptionsNoPersistence(mPrintJob);
+ spooler.setPrintJobState(mPrintJob.getId(), PrintJobInfo.STATE_QUEUED, null);
+ } else {
+ spooler.setPrintJobState(mPrintJob.getId(), PrintJobInfo.STATE_CANCELED, null);
+ }
+ mProgressMessageController.cancel();
+ mPrinterRegistry.setTrackedPrinter(null);
+ mSpoolerProvider.destroy();
+ mPrintedDocument.finish();
+ mPrintedDocument.destroy();
+ }
+
+ mPrinterAvailabilityDetector.cancel();
+
+ super.onPause();
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ event.startTracking();
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_BACK
+ && event.isTracking() && !event.isCanceled()) {
+ cancelPrint();
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public void onActionPerformed() {
+ switch (mState) {
+ case STATE_UPDATE_FAILED: {
+ if (canUpdateDocument()) {
+ updateDocument(true, true);
+ ensurePreviewUiShown();
+ mState = STATE_CONFIGURING;
+ updateOptionsUi();
+ }
+ } break;
+
+ case STATE_CREATE_FILE_FAILED: {
+ mState = STATE_CONFIGURING;
+ ensurePreviewUiShown();
+ updateOptionsUi();
+ } break;
+ }
+ }
+
+ @Override
+ public void onCancelRequest() {
+ if (mPrintedDocument.isUpdating()) {
+ mPrintedDocument.cancel();
+ }
+ }
+
+ public void onUpdateCanceled() {
+ mProgressMessageController.cancel();
+ ensurePreviewUiShown();
+ finishIfConfirmedOrCanceled();
+ updateOptionsUi();
+ }
+
+ @Override
+ public void onUpdateCompleted(RemotePrintDocument.RemotePrintDocumentInfo document) {
+ mProgressMessageController.cancel();
+ ensurePreviewUiShown();
+
+ // Update the print job with the info for the written document. The page
+ // count we get from the remote document is the pages in the document from
+ // the app perspective but the print job should contain the page count from
+ // print service perspective which is the pages in the written PDF not the
+ // pages in the printed document.
+ PrintDocumentInfo info = document.info;
+ if (info == null) {
+ return;
+ }
+ final int pageCount = PageRangeUtils.getNormalizedPageCount(document.writtenPages,
+ info.getPageCount());
+ PrintDocumentInfo adjustedInfo = new PrintDocumentInfo.Builder(info.getName())
+ .setContentType(info.getContentType())
+ .setPageCount(pageCount)
+ .build();
+ mPrintJob.setDocumentInfo(adjustedInfo);
+ mPrintJob.setPages(document.printedPages);
+ finishIfConfirmedOrCanceled();
+ updateOptionsUi();
+ }
+
+ @Override
+ public void onUpdateFailed(CharSequence error) {
+ mState = STATE_UPDATE_FAILED;
+ ensureErrorUiShown(error, PrintErrorFragment.ACTION_RETRY);
+ updateOptionsUi();
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case ACTIVITY_REQUEST_CREATE_FILE: {
+ onStartCreateDocumentActivityResult(resultCode, data);
+ } break;
+
+ case ACTIVITY_REQUEST_SELECT_PRINTER: {
+ onSelectPrinterActivityResult(resultCode, data);
+ } break;
+
+ case ACTIVITY_REQUEST_POPULATE_ADVANCED_PRINT_OPTIONS: {
+ onAdvancedPrintOptionsActivityResult(resultCode, data);
+ } break;
+ }
+ }
+
+ private void startCreateDocumentActivity() {
+ PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
+ if (info == null) {
+ return;
+ }
+ Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+ intent.setType("application/pdf");
+ intent.putExtra(Intent.EXTRA_TITLE, info.getName());
+ intent.putExtra(DocumentsContract.EXTRA_PACKAGE_NAME, mCallingPackageName);
+ startActivityForResult(intent, ACTIVITY_REQUEST_CREATE_FILE);
+ }
+
+ private void onStartCreateDocumentActivityResult(int resultCode, Intent data) {
+ if (resultCode == RESULT_OK && data != null) {
+ Uri uri = data.getData();
+ mPrintedDocument.writeContent(getContentResolver(), uri);
+ finish();
+ } else if (resultCode == RESULT_CANCELED) {
+ mState = STATE_CONFIGURING;
+ updateOptionsUi();
+ } else {
+ ensureErrorUiShown(getString(R.string.print_write_error_message),
+ PrintErrorFragment.ACTION_CONFIRM);
+ mState = STATE_CREATE_FILE_FAILED;
+ updateOptionsUi();
+ }
+ }
+
+ private void startSelectPrinterActivity() {
+ Intent intent = new Intent(this, SelectPrinterActivity.class);
+ startActivityForResult(intent, ACTIVITY_REQUEST_SELECT_PRINTER);
+ }
+
+ private void onSelectPrinterActivityResult(int resultCode, Intent data) {
+ if (resultCode == RESULT_OK && data != null) {
+ PrinterId printerId = data.getParcelableExtra(INTENT_EXTRA_PRINTER_ID);
+ if (printerId != null) {
+ mDestinationSpinnerAdapter.ensurePrinterInVisibleAdapterPosition(printerId);
+ final int index = mDestinationSpinnerAdapter.getPrinterIndex(printerId);
+ if (index != AdapterView.INVALID_POSITION) {
+ mDestinationSpinner.setSelection(index);
+ return;
+ }
+ }
+ }
+
+ PrinterId printerId = mOldCurrentPrinter.getId();
+ final int index = mDestinationSpinnerAdapter.getPrinterIndex(printerId);
+ mDestinationSpinner.setSelection(index);
+ }
+
+ private void startAdvancedPrintOptionsActivity(PrinterInfo printer) {
+ ComponentName serviceName = printer.getId().getServiceName();
+
+ String activityName = PrintOptionUtils.getAdvancedOptionsActivityName(this, serviceName);
+ if (TextUtils.isEmpty(activityName)) {
+ return;
+ }
+
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setComponent(new ComponentName(serviceName.getPackageName(), activityName));
+
+ List<ResolveInfo> resolvedActivities = getPackageManager()
+ .queryIntentActivities(intent, 0);
+ if (resolvedActivities.isEmpty()) {
+ return;
+ }
+
+ // The activity is a component name, therefore it is one or none.
+ if (resolvedActivities.get(0).activityInfo.exported) {
+ intent.putExtra(PrintService.EXTRA_PRINT_JOB_INFO, mPrintJob);
+ intent.putExtra(PrintService.EXTRA_PRINTER_INFO, printer);
+
+ // This is external activity and may not be there.
+ try {
+ startActivityForResult(intent, ACTIVITY_REQUEST_POPULATE_ADVANCED_PRINT_OPTIONS);
+ } catch (ActivityNotFoundException anfe) {
+ Log.e(LOG_TAG, "Error starting activity for intent: " + intent, anfe);
+ }
+ }
+ }
+
+ private void onAdvancedPrintOptionsActivityResult(int resultCode, Intent data) {
+ if (resultCode != RESULT_OK || data == null) {
+ return;
+ }
+
+ PrintJobInfo printJobInfo = data.getParcelableExtra(PrintService.EXTRA_PRINT_JOB_INFO);
+
+ if (printJobInfo == null) {
+ return;
+ }
+
+ // Take the advanced options without interpretation.
+ mPrintJob.setAdvancedOptions(printJobInfo.getAdvancedOptions());
+
+ // Take copies without interpretation as the advanced print dialog
+ // cannot create a print job info with invalid copies.
+ mCopiesEditText.setText(String.valueOf(printJobInfo.getCopies()));
+ mPrintJob.setCopies(printJobInfo.getCopies());
+
+ PrintAttributes currAttributes = mPrintJob.getAttributes();
+ PrintAttributes newAttributes = printJobInfo.getAttributes();
+
+ // Take the media size only if the current printer supports is.
+ MediaSize oldMediaSize = currAttributes.getMediaSize();
+ MediaSize newMediaSize = newAttributes.getMediaSize();
+ if (!oldMediaSize.equals(newMediaSize)) {
+ final int mediaSizeCount = mMediaSizeSpinnerAdapter.getCount();
+ MediaSize newMediaSizePortrait = newAttributes.getMediaSize().asPortrait();
+ for (int i = 0; i < mediaSizeCount; i++) {
+ MediaSize supportedSizePortrait = mMediaSizeSpinnerAdapter.getItem(i).value.asPortrait();
+ if (supportedSizePortrait.equals(newMediaSizePortrait)) {
+ currAttributes.setMediaSize(newMediaSize);
+ mMediaSizeSpinner.setSelection(i);
+ if (currAttributes.getMediaSize().isPortrait()) {
+ if (mOrientationSpinner.getSelectedItemPosition() != 0) {
+ mOrientationSpinner.setSelection(0);
+ }
+ } else {
+ if (mOrientationSpinner.getSelectedItemPosition() != 1) {
+ mOrientationSpinner.setSelection(1);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ // Take the color mode only if the current printer supports it.
+ final int currColorMode = currAttributes.getColorMode();
+ final int newColorMode = newAttributes.getColorMode();
+ if (currColorMode != newColorMode) {
+ final int colorModeCount = mColorModeSpinner.getCount();
+ for (int i = 0; i < colorModeCount; i++) {
+ final int supportedColorMode = mColorModeSpinnerAdapter.getItem(i).value;
+ if (supportedColorMode == newColorMode) {
+ currAttributes.setColorMode(newColorMode);
+ mColorModeSpinner.setSelection(i);
+ break;
+ }
+ }
+ }
+
+ // Take the page range only if it is valid.
+ PageRange[] pageRanges = printJobInfo.getPages();
+ if (pageRanges != null && pageRanges.length > 0) {
+ pageRanges = PageRangeUtils.normalize(pageRanges);
+
+ PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
+ final int pageCount = (info != null) ? info.getPageCount() : 0;
+
+ // Handle the case where all pages are specified explicitly
+ // instead of the *all pages* constant.
+ if (pageRanges.length == 1) {
+ if (pageRanges[0].getStart() == 0 && pageRanges[0].getEnd() == pageCount - 1) {
+ pageRanges[0] = PageRange.ALL_PAGES;
+ }
+ }
+
+ if (Arrays.equals(pageRanges, ALL_PAGES_ARRAY)) {
+ mPrintJob.setPages(pageRanges);
+
+ if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
+ mRangeOptionsSpinner.setSelection(0);
+ }
+ } else if (pageRanges[0].getStart() >= 0
+ && pageRanges[pageRanges.length - 1].getEnd() < pageCount) {
+ mPrintJob.setPages(pageRanges);
+
+ if (mRangeOptionsSpinner.getSelectedItemPosition() != 1) {
+ mRangeOptionsSpinner.setSelection(1);
+ }
+
+ StringBuilder builder = new StringBuilder();
+ final int pageRangeCount = pageRanges.length;
+ for (int i = 0; i < pageRangeCount; i++) {
+ if (builder.length() > 0) {
+ builder.append(',');
+ }
+
+ final int shownStartPage;
+ final int shownEndPage;
+ PageRange pageRange = pageRanges[i];
+ if (pageRange.equals(PageRange.ALL_PAGES)) {
+ shownStartPage = 1;
+ shownEndPage = pageCount;
+ } else {
+ shownStartPage = pageRange.getStart() + 1;
+ shownEndPage = pageRange.getEnd() + 1;
+ }
+
+ builder.append(shownStartPage);
+
+ if (shownStartPage != shownEndPage) {
+ builder.append('-');
+ builder.append(shownEndPage);
+ }
+ }
+ mPageRangeEditText.setText(builder.toString());
+ }
+ }
+
+ // Update the content if needed.
+ if (canUpdateDocument()) {
+ updateDocument(true, false);
+ }
+ }
+
+ private void ensureProgressUiShown() {
+ if (mUiState != UI_STATE_PROGRESS) {
+ mUiState = UI_STATE_PROGRESS;
+ Fragment fragment = PrintProgressFragment.newInstance();
+ showFragment(fragment);
+ }
+ }
+
+ private void ensurePreviewUiShown() {
+ if (mUiState != UI_STATE_PREVIEW) {
+ mUiState = UI_STATE_PREVIEW;
+ Fragment fragment = PrintPreviewFragment.newInstance();
+ showFragment(fragment);
+ }
+ }
+
+ private void ensureErrorUiShown(CharSequence message, int action) {
+ if (mUiState != UI_STATE_ERROR) {
+ mUiState = UI_STATE_ERROR;
+ Fragment fragment = PrintErrorFragment.newInstance(message, action);
+ showFragment(fragment);
+ }
+ }
+
+ private void showFragment(Fragment fragment) {
+ FragmentTransaction transaction = getFragmentManager().beginTransaction();
+ Fragment oldFragment = getFragmentManager().findFragmentById(
+ R.id.embedded_content_container);
+ if (oldFragment != null) {
+ transaction.remove(oldFragment);
+ }
+ transaction.add(R.id.embedded_content_container, fragment);
+ transaction.commit();
+ }
+
+ private void requestCreatePdfFileOrFinish() {
+ if (getCurrentPrinter() == mDestinationSpinnerAdapter.getPdfPrinter()) {
+ startCreateDocumentActivity();
+ } else {
+ finish();
+ }
+ }
+
+ private void finishIfConfirmedOrCanceled() {
+ if (mState == STATE_PRINT_CONFIRMED) {
+ requestCreatePdfFileOrFinish();
+ } else if (mState == STATE_PRINT_CANCELED) {
+ finish();
+ }
+ }
+
+ private void updatePrintAttributesFromCapabilities(PrinterCapabilitiesInfo capabilities) {
+ PrintAttributes defaults = capabilities.getDefaults();
+
+ // Sort the media sizes based on the current locale.
+ List<MediaSize> sortedMediaSizes = new ArrayList<>(capabilities.getMediaSizes());
+ Collections.sort(sortedMediaSizes, mMediaSizeComparator);
+
+ PrintAttributes attributes = mPrintJob.getAttributes();
+
+ // Media size.
+ MediaSize currMediaSize = attributes.getMediaSize();
+ if (currMediaSize == null) {
+ attributes.setMediaSize(defaults.getMediaSize());
+ } else {
+ boolean foundCurrentMediaSize = false;
+ // Try to find the current media size in the capabilities as
+ // it may be in a different orientation.
+ MediaSize currMediaSizePortrait = currMediaSize.asPortrait();
+ final int mediaSizeCount = sortedMediaSizes.size();
+ for (int i = 0; i < mediaSizeCount; i++) {
+ MediaSize mediaSize = sortedMediaSizes.get(i);
+ if (currMediaSizePortrait.equals(mediaSize.asPortrait())) {
+ attributes.setMediaSize(currMediaSize);
+ foundCurrentMediaSize = true;
+ break;
+ }
+ }
+ // If we did not find the current media size fall back to default.
+ if (!foundCurrentMediaSize) {
+ attributes.setMediaSize(defaults.getMediaSize());
+ }
+ }
+
+ // Color mode.
+ final int colorMode = attributes.getColorMode();
+ if ((capabilities.getColorModes() & colorMode) == 0) {
+ attributes.setColorMode(defaults.getColorMode());
+ }
+
+ // Resolution
+ Resolution resolution = attributes.getResolution();
+ if (resolution == null || !capabilities.getResolutions().contains(resolution)) {
+ attributes.setResolution(defaults.getResolution());
+ }
+
+ // Margins.
+ attributes.setMinMargins(defaults.getMinMargins());
+ }
+
+ private boolean updateDocument(boolean preview, boolean clearLastError) {
+ if (!clearLastError && mPrintedDocument.hasUpdateError()) {
+ return false;
+ }
+
+ if (clearLastError && mPrintedDocument.hasUpdateError()) {
+ mPrintedDocument.clearUpdateError();
+ }
+
+ if (mRequestedPages != null && mRequestedPages.length > 0) {
+ final PageRange[] pages;
+ if (preview) {
+ final int firstPage = mRequestedPages[0].getStart();
+ pages = new PageRange[]{new PageRange(firstPage, firstPage)};
+ } else {
+ pages = mRequestedPages;
+ }
+ final boolean willUpdate = mPrintedDocument.update(mPrintJob.getAttributes(),
+ pages, preview);
+
+ if (willUpdate) {
+ mProgressMessageController.post();
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void addCurrentPrinterToHistory() {
+ PrinterInfo currentPrinter = getCurrentPrinter();
+ if (currentPrinter != null) {
+ PrinterId fakePdfPrinterId = mDestinationSpinnerAdapter.getPdfPrinter().getId();
+ if (!currentPrinter.getId().equals(fakePdfPrinterId)) {
+ mPrinterRegistry.addHistoricalPrinter(currentPrinter);
+ }
+ }
+ }
+
+ private PrinterInfo getCurrentPrinter() {
+ return ((PrinterHolder) mDestinationSpinner.getSelectedItem()).printer;
+ }
+
+ private void cancelPrint() {
+ mState = STATE_PRINT_CANCELED;
+ updateOptionsUi();
+ if (mPrintedDocument.isUpdating()) {
+ mPrintedDocument.cancel();
+ }
+ finish();
+ }
+
+ private void confirmPrint() {
+ mState = STATE_PRINT_CONFIRMED;
+ updateOptionsUi();
+ if (canUpdateDocument()) {
+ updateDocument(false, false);
+ }
+ addCurrentPrinterToHistory();
+ if (!mPrintedDocument.isUpdating()) {
+ requestCreatePdfFileOrFinish();
+ }
+ }
+
+ private void bindUi() {
+ // Summary
+ mSummaryCopies = (TextView) findViewById(R.id.copies_count_summary);
+ mSummaryPaperSize = (TextView) findViewById(R.id.paper_size_summary);
+
+ // Options container
+ mOptionsContent = (ContentView) findViewById(R.id.options_content);
+ mOptionsContent.setOptionsStateChangeListener(new OptionsStateChangeListener() {
+ @Override
+ public void onOptionsOpened() {
+ // TODO: Update preview.
+ }
+
+ @Override
+ public void onOptionsClosed() {
+ // TODO: Update preview.
+ }
+ });
+
+ OnItemSelectedListener itemSelectedListener = new MyOnItemSelectedListener();
+ OnClickListener clickListener = new MyClickListener();
+
+ // Copies
+ mCopiesEditText = (EditText) findViewById(R.id.copies_edittext);
+ mCopiesEditText.setOnFocusChangeListener(mSelectAllOnFocusListener);
+ mCopiesEditText.setText(MIN_COPIES_STRING);
+ mCopiesEditText.setSelection(mCopiesEditText.getText().length());
+ mCopiesEditText.addTextChangedListener(new EditTextWatcher());
+
+ // Destination.
+ mDestinationSpinnerAdapter.registerDataSetObserver(new PrintersObserver());
+ mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner);
+ mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter);
+ mDestinationSpinner.setOnItemSelectedListener(itemSelectedListener);
+ mDestinationSpinner.setSelection(0);
+
+ // Media size.
+ mMediaSizeSpinnerAdapter = new ArrayAdapter<>(
+ this, R.layout.spinner_dropdown_item, R.id.title);
+ mMediaSizeSpinner = (Spinner) findViewById(R.id.paper_size_spinner);
+ mMediaSizeSpinner.setAdapter(mMediaSizeSpinnerAdapter);
+ mMediaSizeSpinner.setOnItemSelectedListener(itemSelectedListener);
+
+ // Color mode.
+ mColorModeSpinnerAdapter = new ArrayAdapter<>(
+ this, R.layout.spinner_dropdown_item, R.id.title);
+ mColorModeSpinner = (Spinner) findViewById(R.id.color_spinner);
+ mColorModeSpinner.setAdapter(mColorModeSpinnerAdapter);
+ mColorModeSpinner.setOnItemSelectedListener(itemSelectedListener);
+
+ // Orientation
+ mOrientationSpinnerAdapter = new ArrayAdapter<>(
+ this, R.layout.spinner_dropdown_item, R.id.title);
+ String[] orientationLabels = getResources().getStringArray(
+ R.array.orientation_labels);
+ mOrientationSpinnerAdapter.add(new SpinnerItem<>(
+ ORIENTATION_PORTRAIT, orientationLabels[0]));
+ mOrientationSpinnerAdapter.add(new SpinnerItem<>(
+ ORIENTATION_LANDSCAPE, orientationLabels[1]));
+ mOrientationSpinner = (Spinner) findViewById(R.id.orientation_spinner);
+ mOrientationSpinner.setAdapter(mOrientationSpinnerAdapter);
+ mOrientationSpinner.setOnItemSelectedListener(itemSelectedListener);
+
+ // Range options
+ ArrayAdapter<SpinnerItem<Integer>> rangeOptionsSpinnerAdapter =
+ new ArrayAdapter<>(this, R.layout.spinner_dropdown_item, R.id.title);
+ final int[] rangeOptionsValues = getResources().getIntArray(
+ R.array.page_options_values);
+ String[] rangeOptionsLabels = getResources().getStringArray(
+ R.array.page_options_labels);
+ final int rangeOptionsCount = rangeOptionsLabels.length;
+ for (int i = 0; i < rangeOptionsCount; i++) {
+ rangeOptionsSpinnerAdapter.add(new SpinnerItem<>(
+ rangeOptionsValues[i], rangeOptionsLabels[i]));
+ }
+ mPageRangeOptionsTitle = (TextView) findViewById(R.id.range_options_title);
+ mRangeOptionsSpinner = (Spinner) findViewById(R.id.range_options_spinner);
+ mRangeOptionsSpinner.setAdapter(rangeOptionsSpinnerAdapter);
+ mRangeOptionsSpinner.setOnItemSelectedListener(itemSelectedListener);
+
+ // Page range
+ mPageRangeTitle = (TextView) findViewById(R.id.page_range_title);
+ mPageRangeEditText = (EditText) findViewById(R.id.page_range_edittext);
+ mPageRangeEditText.setOnFocusChangeListener(mSelectAllOnFocusListener);
+ mPageRangeEditText.addTextChangedListener(new RangeTextWatcher());
+
+ // Advanced options button.
+ mAdvancedPrintOptionsContainer = findViewById(R.id.more_options_container);
+ mMoreOptionsButton = (Button) findViewById(R.id.more_options_button);
+ mMoreOptionsButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ PrinterInfo currentPrinter = getCurrentPrinter();
+ if (currentPrinter != null) {
+ startAdvancedPrintOptionsActivity(currentPrinter);
+ }
+ }
+ });
+
+ // Print button
+ mPrintButton = (ImageView) findViewById(R.id.print_button);
+ mPrintButton.setOnClickListener(clickListener);
+ }
+
+ private final class MyClickListener implements OnClickListener {
+ @Override
+ public void onClick(View view) {
+ if (view == mPrintButton) {
+ PrinterInfo currentPrinter = getCurrentPrinter();
+ if (currentPrinter != null) {
+ confirmPrint();
+ } else {
+ cancelPrint();
+ }
+ } else if (view == mMoreOptionsButton) {
+ PrinterInfo currentPrinter = getCurrentPrinter();
+ if (currentPrinter != null) {
+ startAdvancedPrintOptionsActivity(currentPrinter);
+ }
+ }
+ }
+ }
+
+ private static boolean canPrint(PrinterInfo printer) {
+ return printer.getCapabilities() != null
+ && printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE;
+ }
+
+ private void updateOptionsUi() {
+ // Always update the summary.
+ if (!TextUtils.isEmpty(mCopiesEditText.getText())) {
+ mSummaryCopies.setText(mCopiesEditText.getText());
+ }
+
+ final int selectedMediaIndex = mMediaSizeSpinner.getSelectedItemPosition();
+ if (selectedMediaIndex >= 0) {
+ SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(selectedMediaIndex);
+ mSummaryPaperSize.setText(mediaItem.label);
+ }
+
+ if (mState == STATE_PRINT_CONFIRMED
+ || mState == STATE_PRINT_CANCELED
+ || mState == STATE_UPDATE_FAILED
+ || mState == STATE_CREATE_FILE_FAILED
+ || mState == STATE_PRINTER_UNAVAILABLE) {
+ if (mState != STATE_PRINTER_UNAVAILABLE) {
+ mDestinationSpinner.setEnabled(false);
+ }
+ mCopiesEditText.setEnabled(false);
+ mMediaSizeSpinner.setEnabled(false);
+ mColorModeSpinner.setEnabled(false);
+ mOrientationSpinner.setEnabled(false);
+ mRangeOptionsSpinner.setEnabled(false);
+ mPageRangeEditText.setEnabled(false);
+ mPrintButton.setEnabled(false);
+ mMoreOptionsButton.setEnabled(false);
+ return;
+ }
+
+ // If no current printer, or it has no capabilities, or it is not
+ // available, we disable all print options except the destination.
+ PrinterInfo currentPrinter = getCurrentPrinter();
+ if (currentPrinter == null || !canPrint(currentPrinter)) {
+ mCopiesEditText.setEnabled(false);
+ mMediaSizeSpinner.setEnabled(false);
+ mColorModeSpinner.setEnabled(false);
+ mOrientationSpinner.setEnabled(false);
+ mRangeOptionsSpinner.setEnabled(false);
+ mPageRangeEditText.setEnabled(false);
+ mPrintButton.setEnabled(false);
+ mMoreOptionsButton.setEnabled(false);
+ return;
+ }
+
+ PrinterCapabilitiesInfo capabilities = currentPrinter.getCapabilities();
+ PrintAttributes defaultAttributes = capabilities.getDefaults();
+
+ // Media size.
+ mMediaSizeSpinner.setEnabled(true);
+
+ List<MediaSize> mediaSizes = new ArrayList<>(capabilities.getMediaSizes());
+ // Sort the media sizes based on the current locale.
+ Collections.sort(mediaSizes, mMediaSizeComparator);
+
+ PrintAttributes attributes = mPrintJob.getAttributes();
+
+ // If the media sizes changed, we update the adapter and the spinner.
+ boolean mediaSizesChanged = false;
+ final int mediaSizeCount = mediaSizes.size();
+ if (mediaSizeCount != mMediaSizeSpinnerAdapter.getCount()) {
+ mediaSizesChanged = true;
+ } else {
+ for (int i = 0; i < mediaSizeCount; i++) {
+ if (!mediaSizes.get(i).equals(mMediaSizeSpinnerAdapter.getItem(i).value)) {
+ mediaSizesChanged = true;
+ break;
+ }
+ }
+ }
+ if (mediaSizesChanged) {
+ // Remember the old media size to try selecting it again.
+ int oldMediaSizeNewIndex = AdapterView.INVALID_POSITION;
+ MediaSize oldMediaSize = attributes.getMediaSize();
+
+ // Rebuild the adapter data.
+ mMediaSizeSpinnerAdapter.clear();
+ for (int i = 0; i < mediaSizeCount; i++) {
+ MediaSize mediaSize = mediaSizes.get(i);
+ if (oldMediaSize != null
+ && mediaSize.asPortrait().equals(oldMediaSize.asPortrait())) {
+ // Update the index of the old selection.
+ oldMediaSizeNewIndex = i;
+ }
+ mMediaSizeSpinnerAdapter.add(new SpinnerItem<>(
+ mediaSize, mediaSize.getLabel(getPackageManager())));
+ }
+
+ if (oldMediaSizeNewIndex != AdapterView.INVALID_POSITION) {
+ // Select the old media size - nothing really changed.
+ if (mMediaSizeSpinner.getSelectedItemPosition() != oldMediaSizeNewIndex) {
+ mMediaSizeSpinner.setSelection(oldMediaSizeNewIndex);
+ }
+ } else {
+ // Select the first or the default.
+ final int mediaSizeIndex = Math.max(mediaSizes.indexOf(
+ defaultAttributes.getMediaSize()), 0);
+ if (mMediaSizeSpinner.getSelectedItemPosition() != mediaSizeIndex) {
+ mMediaSizeSpinner.setSelection(mediaSizeIndex);
+ }
+ // Respect the orientation of the old selection.
+ if (oldMediaSize != null) {
+ if (oldMediaSize.isPortrait()) {
+ attributes.setMediaSize(mMediaSizeSpinnerAdapter
+ .getItem(mediaSizeIndex).value.asPortrait());
+ } else {
+ attributes.setMediaSize(mMediaSizeSpinnerAdapter
+ .getItem(mediaSizeIndex).value.asLandscape());
+ }
+ }
+ }
+ }
+
+ // Color mode.
+ mColorModeSpinner.setEnabled(true);
+ final int colorModes = capabilities.getColorModes();
+
+ // If the color modes changed, we update the adapter and the spinner.
+ boolean colorModesChanged = false;
+ if (Integer.bitCount(colorModes) != mColorModeSpinnerAdapter.getCount()) {
+ colorModesChanged = true;
+ } else {
+ int remainingColorModes = colorModes;
+ int adapterIndex = 0;
+ while (remainingColorModes != 0) {
+ final int colorBitOffset = Integer.numberOfTrailingZeros(remainingColorModes);
+ final int colorMode = 1 << colorBitOffset;
+ remainingColorModes &= ~colorMode;
+ if (colorMode != mColorModeSpinnerAdapter.getItem(adapterIndex).value) {
+ colorModesChanged = true;
+ break;
+ }
+ adapterIndex++;
+ }
+ }
+ if (colorModesChanged) {
+ // Remember the old color mode to try selecting it again.
+ int oldColorModeNewIndex = AdapterView.INVALID_POSITION;
+ final int oldColorMode = attributes.getColorMode();
+
+ // Rebuild the adapter data.
+ mColorModeSpinnerAdapter.clear();
+ String[] colorModeLabels = getResources().getStringArray(R.array.color_mode_labels);
+ int remainingColorModes = colorModes;
+ while (remainingColorModes != 0) {
+ final int colorBitOffset = Integer.numberOfTrailingZeros(remainingColorModes);
+ final int colorMode = 1 << colorBitOffset;
+ if (colorMode == oldColorMode) {
+ // Update the index of the old selection.
+ oldColorModeNewIndex = colorBitOffset;
+ }
+ remainingColorModes &= ~colorMode;
+ mColorModeSpinnerAdapter.add(new SpinnerItem<>(colorMode,
+ colorModeLabels[colorBitOffset]));
+ }
+ if (oldColorModeNewIndex != AdapterView.INVALID_POSITION) {
+ // Select the old color mode - nothing really changed.
+ if (mColorModeSpinner.getSelectedItemPosition() != oldColorModeNewIndex) {
+ mColorModeSpinner.setSelection(oldColorModeNewIndex);
+ }
+ } else {
+ // Select the default.
+ final int selectedColorMode = colorModes & defaultAttributes.getColorMode();
+ final int itemCount = mColorModeSpinnerAdapter.getCount();
+ for (int i = 0; i < itemCount; i++) {
+ SpinnerItem<Integer> item = mColorModeSpinnerAdapter.getItem(i);
+ if (selectedColorMode == item.value) {
+ if (mColorModeSpinner.getSelectedItemPosition() != i) {
+ mColorModeSpinner.setSelection(i);
+ }
+ attributes.setColorMode(selectedColorMode);
+ }
+ }
+ }
+ }
+
+ // Orientation
+ mOrientationSpinner.setEnabled(true);
+ MediaSize mediaSize = attributes.getMediaSize();
+ if (mediaSize != null) {
+ if (mediaSize.isPortrait()
+ && mOrientationSpinner.getSelectedItemPosition() != 0) {
+ mOrientationSpinner.setSelection(0);
+ } else if (!mediaSize.isPortrait()
+ && mOrientationSpinner.getSelectedItemPosition() != 1) {
+ mOrientationSpinner.setSelection(1);
+ }
+ }
+
+ // Range options
+ PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
+ if (info != null && info.getPageCount() > 0) {
+ if (info.getPageCount() == 1) {
+ mRangeOptionsSpinner.setEnabled(false);
+ } else {
+ mRangeOptionsSpinner.setEnabled(true);
+ if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
+ if (!mPageRangeEditText.isEnabled()) {
+ mPageRangeEditText.setEnabled(true);
+ mPageRangeEditText.setVisibility(View.VISIBLE);
+ mPageRangeTitle.setVisibility(View.VISIBLE);
+ mPageRangeEditText.requestFocus();
+ InputMethodManager imm = (InputMethodManager)
+ getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(mPageRangeEditText, 0);
+ }
+ } else {
+ mPageRangeEditText.setEnabled(false);
+ mPageRangeEditText.setVisibility(View.INVISIBLE);
+ mPageRangeTitle.setVisibility(View.INVISIBLE);
+ }
+ }
+ String title = (info.getPageCount() != PrintDocumentInfo.PAGE_COUNT_UNKNOWN)
+ ? getString(R.string.label_pages, String.valueOf(info.getPageCount()))
+ : getString(R.string.page_count_unknown);
+ mPageRangeOptionsTitle.setText(title);
+ } else {
+ if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
+ mRangeOptionsSpinner.setSelection(0);
+ }
+ mRangeOptionsSpinner.setEnabled(false);
+ mPageRangeOptionsTitle.setText(getString(R.string.page_count_unknown));
+ mPageRangeEditText.setEnabled(false);
+ mPageRangeEditText.setVisibility(View.INVISIBLE);
+ mPageRangeTitle.setVisibility(View.INVISIBLE);
+ }
+
+ // Advanced print options
+ ComponentName serviceName = currentPrinter.getId().getServiceName();
+ if (!TextUtils.isEmpty(PrintOptionUtils.getAdvancedOptionsActivityName(
+ this, serviceName))) {
+ mAdvancedPrintOptionsContainer.setVisibility(View.VISIBLE);
+ mMoreOptionsButton.setEnabled(true);
+ } else {
+ mAdvancedPrintOptionsContainer.setVisibility(View.GONE);
+ mMoreOptionsButton.setEnabled(false);
+ }
+
+ // Print
+ if (mDestinationSpinnerAdapter.getPdfPrinter() != currentPrinter) {
+ mPrintButton.setImageResource(com.android.internal.R.drawable.ic_print);
+ } else {
+ mPrintButton.setImageResource(com.android.internal.R.drawable.ic_menu_save);
+ }
+ if ((mRangeOptionsSpinner.getSelectedItemPosition() == 1
+ && (TextUtils.isEmpty(mPageRangeEditText.getText()) || hasErrors()))
+ || (mRangeOptionsSpinner.getSelectedItemPosition() == 0
+ && (mPrintedDocument.getDocumentInfo() == null || hasErrors()))) {
+ mPrintButton.setEnabled(false);
+ } else {
+ mPrintButton.setEnabled(true);
+ }
+
+ // Copies
+ if (mDestinationSpinnerAdapter.getPdfPrinter() != currentPrinter) {
+ mCopiesEditText.setEnabled(true);
+ } else {
+ mCopiesEditText.setEnabled(false);
+ }
+ if (mCopiesEditText.getError() == null
+ && TextUtils.isEmpty(mCopiesEditText.getText())) {
+ mCopiesEditText.setText(String.valueOf(MIN_COPIES));
+ mCopiesEditText.requestFocus();
+ }
+ }
+
+ private PageRange[] computeRequestedPages() {
+ if (hasErrors()) {
+ return null;
+ }
+
+ if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
+ List<PageRange> pageRanges = new ArrayList<>();
+ mStringCommaSplitter.setString(mPageRangeEditText.getText().toString());
+
+ while (mStringCommaSplitter.hasNext()) {
+ String range = mStringCommaSplitter.next().trim();
+ if (TextUtils.isEmpty(range)) {
+ continue;
+ }
+ final int dashIndex = range.indexOf('-');
+ final int fromIndex;
+ final int toIndex;
+
+ if (dashIndex > 0) {
+ fromIndex = Integer.parseInt(range.substring(0, dashIndex).trim()) - 1;
+ // It is possible that the dash is at the end since the input
+ // verification can has to allow the user to keep entering if
+ // this would lead to a valid input. So we handle this.
+ if (dashIndex < range.length() - 1) {
+ String fromString = range.substring(dashIndex + 1, range.length()).trim();
+ toIndex = Integer.parseInt(fromString) - 1;
+ } else {
+ toIndex = fromIndex;
+ }
+ } else {
+ fromIndex = toIndex = Integer.parseInt(range) - 1;
+ }
+
+ PageRange pageRange = new PageRange(Math.min(fromIndex, toIndex),
+ Math.max(fromIndex, toIndex));
+ pageRanges.add(pageRange);
+ }
+
+ PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
+ pageRanges.toArray(pageRangesArray);
+
+ return PageRangeUtils.normalize(pageRangesArray);
+ }
+
+ return ALL_PAGES_ARRAY;
+ }
+
+ private boolean hasErrors() {
+ return (mCopiesEditText.getError() != null)
+ || (mPageRangeEditText.getVisibility() == View.VISIBLE
+ && mPageRangeEditText.getError() != null);
+ }
+
+ public void onPrinterAvailable(PrinterInfo printer) {
+ PrinterInfo currentPrinter = getCurrentPrinter();
+ if (currentPrinter.equals(printer)) {
+ mState = STATE_CONFIGURING;
+ if (canUpdateDocument()) {
+ updateDocument(true, false);
+ }
+ ensurePreviewUiShown();
+ updateOptionsUi();
+ }
+ }
+
+ public void onPrinterUnavailable(PrinterInfo printer) {
+ if (getCurrentPrinter().getId().equals(printer.getId())) {
+ mState = STATE_PRINTER_UNAVAILABLE;
+ if (mPrintedDocument.isUpdating()) {
+ mPrintedDocument.cancel();
+ }
+ ensureErrorUiShown(getString(R.string.print_error_printer_unavailable),
+ PrintErrorFragment.ACTION_NONE);
+ updateOptionsUi();
+ }
+ }
+
+ private final class SpinnerItem<T> {
+ final T value;
+ final CharSequence label;
+
+ public SpinnerItem(T value, CharSequence label) {
+ this.value = value;
+ this.label = label;
+ }
+
+ public String toString() {
+ return label.toString();
+ }
+ }
+
+ private final class PrinterAvailabilityDetector implements Runnable {
+ private static final long UNAVAILABLE_TIMEOUT_MILLIS = 10000; // 10sec
+
+ private boolean mPosted;
+
+ private boolean mPrinterUnavailable;
+
+ private PrinterInfo mPrinter;
+
+ public void updatePrinter(PrinterInfo printer) {
+ if (printer.equals(mDestinationSpinnerAdapter.getPdfPrinter())) {
+ return;
+ }
+
+ final boolean available = printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE
+ && printer.getCapabilities() != null;
+ final boolean notifyIfAvailable;
+
+ if (mPrinter == null || !mPrinter.getId().equals(printer.getId())) {
+ notifyIfAvailable = true;
+ unpostIfNeeded();
+ mPrinterUnavailable = false;
+ mPrinter = new PrinterInfo.Builder(printer).build();
+ } else {
+ notifyIfAvailable =
+ (mPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE
+ && printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE)
+ || (mPrinter.getCapabilities() == null
+ && printer.getCapabilities() != null);
+ mPrinter.copyFrom(printer);
+ }
+
+ if (available) {
+ unpostIfNeeded();
+ mPrinterUnavailable = false;
+ if (notifyIfAvailable) {
+ onPrinterAvailable(mPrinter);
+ }
+ } else {
+ if (!mPrinterUnavailable) {
+ postIfNeeded();
+ }
+ }
+ }
+
+ public void cancel() {
+ unpostIfNeeded();
+ mPrinterUnavailable = false;
+ }
+
+ private void postIfNeeded() {
+ if (!mPosted) {
+ mPosted = true;
+ mDestinationSpinner.postDelayed(this, UNAVAILABLE_TIMEOUT_MILLIS);
+ }
+ }
+
+ private void unpostIfNeeded() {
+ if (mPosted) {
+ mPosted = false;
+ mDestinationSpinner.removeCallbacks(this);
+ }
+ }
+
+ @Override
+ public void run() {
+ mPosted = false;
+ mPrinterUnavailable = true;
+ onPrinterUnavailable(mPrinter);
+ }
+ }
+
+ private static final class PrinterHolder {
+ PrinterInfo printer;
+ boolean removed;
+
+ public PrinterHolder(PrinterInfo printer) {
+ this.printer = printer;
+ }
+ }
+
+ private final class DestinationAdapter extends BaseAdapter
+ implements PrinterRegistry.OnPrintersChangeListener {
+ private final List<PrinterHolder> mPrinterHolders = new ArrayList<>();
+
+ private final PrinterHolder mFakePdfPrinterHolder;
+
+ public DestinationAdapter() {
+ addPrinters(mPrinterHolders, mPrinterRegistry.getPrinters());
+ mPrinterRegistry.setOnPrintersChangeListener(this);
+ mFakePdfPrinterHolder = new PrinterHolder(createFakePdfPrinter());
+ }
+
+ public PrinterInfo getPdfPrinter() {
+ return mFakePdfPrinterHolder.printer;
+ }
+
+ public int getPrinterIndex(PrinterId printerId) {
+ for (int i = 0; i < getCount(); i++) {
+ PrinterHolder printerHolder = (PrinterHolder) getItem(i);
+ if (printerHolder != null && !printerHolder.removed
+ && printerHolder.printer.getId().equals(printerId)) {
+ return i;
+ }
+ }
+ return AdapterView.INVALID_POSITION;
+ }
+
+ public void ensurePrinterInVisibleAdapterPosition(PrinterId printerId) {
+ final int printerCount = mPrinterHolders.size();
+ for (int i = 0; i < printerCount; i++) {
+ PrinterHolder printerHolder = mPrinterHolders.get(i);
+ if (printerHolder.printer.getId().equals(printerId)) {
+ // If already in the list - do nothing.
+ if (i < getCount() - 2) {
+ return;
+ }
+ // Else replace the last one (two items are not printers).
+ final int lastPrinterIndex = getCount() - 3;
+ mPrinterHolders.set(i, mPrinterHolders.get(lastPrinterIndex));
+ mPrinterHolders.set(lastPrinterIndex, printerHolder);
+ notifyDataSetChanged();
+ return;
+ }
+ }
+ }
+
+ @Override
+ public int getCount() {
+ return Math.min(mPrinterHolders.size() + 2, DEST_ADAPTER_MAX_ITEM_COUNT);
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ Object item = getItem(position);
+ if (item instanceof PrinterHolder) {
+ PrinterHolder printerHolder = (PrinterHolder) item;
+ return !printerHolder.removed
+ && printerHolder.printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE;
+ }
+ return true;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ if (mPrinterHolders.isEmpty()) {
+ if (position == 0) {
+ return mFakePdfPrinterHolder;
+ }
+ } else {
+ if (position < 1) {
+ return mPrinterHolders.get(position);
+ }
+ if (position == 1) {
+ return mFakePdfPrinterHolder;
+ }
+ if (position < getCount() - 1) {
+ return mPrinterHolders.get(position - 1);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ if (mPrinterHolders.isEmpty()) {
+ if (position == 0) {
+ return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF;
+ } else if (position == 1) {
+ return DEST_ADAPTER_ITEM_ID_ALL_PRINTERS;
+ }
+ } else {
+ if (position == 1) {
+ return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF;
+ }
+ if (position == getCount() - 1) {
+ return DEST_ADAPTER_ITEM_ID_ALL_PRINTERS;
+ }
+ }
+ return position;
+ }
+
+ @Override
+ public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ View view = getView(position, convertView, parent);
+ view.setEnabled(isEnabled(position));
+ return view;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(
+ R.layout.printer_dropdown_item, parent, false);
+ }
+
+ CharSequence title = null;
+ CharSequence subtitle = null;
+ Drawable icon = null;
+
+ if (mPrinterHolders.isEmpty()) {
+ if (position == 0 && getPdfPrinter() != null) {
+ PrinterHolder printerHolder = (PrinterHolder) getItem(position);
+ title = printerHolder.printer.getName();
+ icon = getResources().getDrawable(com.android.internal.R.drawable.ic_menu_save);
+ } else if (position == 1) {
+ title = getString(R.string.all_printers);
+ }
+ } else {
+ if (position == 1 && getPdfPrinter() != null) {
+ PrinterHolder printerHolder = (PrinterHolder) getItem(position);
+ title = printerHolder.printer.getName();
+ icon = getResources().getDrawable(com.android.internal.R.drawable.ic_menu_save);
+ } else if (position == getCount() - 1) {
+ title = getString(R.string.all_printers);
+ } else {
+ PrinterHolder printerHolder = (PrinterHolder) getItem(position);
+ title = printerHolder.printer.getName();
+ try {
+ PackageInfo packageInfo = getPackageManager().getPackageInfo(
+ printerHolder.printer.getId().getServiceName().getPackageName(), 0);
+ subtitle = packageInfo.applicationInfo.loadLabel(getPackageManager());
+ icon = packageInfo.applicationInfo.loadIcon(getPackageManager());
+ } catch (NameNotFoundException nnfe) {
+ /* ignore */
+ }
+ }
+ }
+
+ TextView titleView = (TextView) convertView.findViewById(R.id.title);
+ titleView.setText(title);
+
+ TextView subtitleView = (TextView) convertView.findViewById(R.id.subtitle);
+ if (!TextUtils.isEmpty(subtitle)) {
+ subtitleView.setText(subtitle);
+ subtitleView.setVisibility(View.VISIBLE);
+ } else {
+ subtitleView.setText(null);
+ subtitleView.setVisibility(View.GONE);
+ }
+
+ ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
+ if (icon != null) {
+ iconView.setImageDrawable(icon);
+ iconView.setVisibility(View.VISIBLE);
+ } else {
+ iconView.setVisibility(View.INVISIBLE);
+ }
+
+ return convertView;
+ }
+
+ @Override
+ public void onPrintersChanged(List<PrinterInfo> printers) {
+ // We rearrange the printers if the user selects a printer
+ // not shown in the initial short list. Therefore, we have
+ // to keep the printer order.
+
+ // No old printers - do not bother keeping their position.
+ if (mPrinterHolders.isEmpty()) {
+ addPrinters(mPrinterHolders, printers);
+ notifyDataSetChanged();
+ return;
+ }
+
+ // Add the new printers to a map.
+ ArrayMap<PrinterId, PrinterInfo> newPrintersMap = new ArrayMap<>();
+ final int printerCount = printers.size();
+ for (int i = 0; i < printerCount; i++) {
+ PrinterInfo printer = printers.get(i);
+ newPrintersMap.put(printer.getId(), printer);
+ }
+
+ List<PrinterHolder> newPrinterHolders = new ArrayList<>();
+
+ // Update printers we already have which are either updated or removed.
+ // We do not remove printers if the currently selected printer is removed
+ // to prevent the user printing to a wrong printer.
+ final int oldPrinterCount = mPrinterHolders.size();
+ for (int i = 0; i < oldPrinterCount; i++) {
+ PrinterHolder printerHolder = mPrinterHolders.get(i);
+ PrinterId oldPrinterId = printerHolder.printer.getId();
+ PrinterInfo updatedPrinter = newPrintersMap.remove(oldPrinterId);
+ if (updatedPrinter != null) {
+ printerHolder.printer = updatedPrinter;
+ } else {
+ printerHolder.removed = true;
+ }
+ newPrinterHolders.add(printerHolder);
+ }
+
+ // Add the rest of the new printers, i.e. what is left.
+ addPrinters(newPrinterHolders, newPrintersMap.values());
+
+ mPrinterHolders.clear();
+ mPrinterHolders.addAll(newPrinterHolders);
+
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public void onPrintersInvalid() {
+ mPrinterHolders.clear();
+ notifyDataSetInvalidated();
+ }
+
+ public PrinterHolder getPrinterHolder(PrinterId printerId) {
+ final int itemCount = getCount();
+ for (int i = 0; i < itemCount; i++) {
+ Object item = getItem(i);
+ if (item instanceof PrinterHolder) {
+ PrinterHolder printerHolder = (PrinterHolder) item;
+ if (printerId.equals(printerHolder.printer.getId())) {
+ return printerHolder;
+ }
+ }
+ }
+ return null;
+ }
+
+ public void pruneRemovedPrinters() {
+ final int holderCounts = mPrinterHolders.size();
+ for (int i = holderCounts - 1; i >= 0; i--) {
+ PrinterHolder printerHolder = mPrinterHolders.get(i);
+ if (printerHolder.removed) {
+ mPrinterHolders.remove(i);
+ }
+ }
+ }
+
+ private void addPrinters(List<PrinterHolder> list, Collection<PrinterInfo> printers) {
+ for (PrinterInfo printer : printers) {
+ PrinterHolder printerHolder = new PrinterHolder(printer);
+ list.add(printerHolder);
+ }
+ }
+
+ private PrinterInfo createFakePdfPrinter() {
+ MediaSize defaultMediaSize = MediaSizeUtils.getDefault(PrintActivity.this);
+
+ PrinterId printerId = new PrinterId(getComponentName(), "PDF printer");
+
+ PrinterCapabilitiesInfo.Builder builder =
+ new PrinterCapabilitiesInfo.Builder(printerId);
+
+ String[] mediaSizeIds = getResources().getStringArray(R.array.pdf_printer_media_sizes);
+ final int mediaSizeIdCount = mediaSizeIds.length;
+ for (int i = 0; i < mediaSizeIdCount; i++) {
+ String id = mediaSizeIds[i];
+ MediaSize mediaSize = MediaSize.getStandardMediaSizeById(id);
+ builder.addMediaSize(mediaSize, mediaSize.equals(defaultMediaSize));
+ }
+
+ builder.addResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300),
+ true);
+ builder.setColorModes(PrintAttributes.COLOR_MODE_COLOR
+ | PrintAttributes.COLOR_MODE_MONOCHROME, PrintAttributes.COLOR_MODE_COLOR);
+
+ return new PrinterInfo.Builder(printerId, getString(R.string.save_as_pdf),
+ PrinterInfo.STATUS_IDLE).setCapabilities(builder.build()).build();
+ }
+ }
+
+ private final class PrintersObserver extends DataSetObserver {
+ @Override
+ public void onChanged() {
+ PrinterInfo oldPrinterState = mOldCurrentPrinter;
+ if (oldPrinterState == null) {
+ return;
+ }
+
+ PrinterHolder printerHolder = mDestinationSpinnerAdapter.getPrinterHolder(
+ oldPrinterState.getId());
+ if (printerHolder == null) {
+ return;
+ }
+ PrinterInfo newPrinterState = printerHolder.printer;
+
+ if (!printerHolder.removed) {
+ mDestinationSpinnerAdapter.pruneRemovedPrinters();
+ } else {
+ onPrinterUnavailable(newPrinterState);
+ }
+
+ if (oldPrinterState.equals(newPrinterState)) {
+ return;
+ }
+
+ PrinterCapabilitiesInfo oldCapab = oldPrinterState.getCapabilities();
+ PrinterCapabilitiesInfo newCapab = newPrinterState.getCapabilities();
+
+ final boolean hasCapab = newCapab != null;
+ final boolean gotCapab = oldCapab == null && newCapab != null;
+ final boolean lostCapab = oldCapab != null && newCapab == null;
+ final boolean capabChanged = capabilitiesChanged(oldCapab, newCapab);
+
+ final int oldStatus = oldPrinterState.getStatus();
+ final int newStatus = newPrinterState.getStatus();
+
+ final boolean isActive = newStatus != PrinterInfo.STATUS_UNAVAILABLE;
+ final boolean becameActive = (oldStatus == PrinterInfo.STATUS_UNAVAILABLE
+ && oldStatus != newStatus);
+ final boolean becameInactive = (newStatus == PrinterInfo.STATUS_UNAVAILABLE
+ && oldStatus != newStatus);
+
+ mPrinterAvailabilityDetector.updatePrinter(newPrinterState);
+
+ oldPrinterState.copyFrom(newPrinterState);
+
+ if ((isActive && gotCapab) || (becameActive && hasCapab)) {
+ onPrinterAvailable(newPrinterState);
+ } else if ((becameInactive && hasCapab)|| (isActive && lostCapab)) {
+ onPrinterUnavailable(newPrinterState);
+ }
+
+ if (hasCapab && capabChanged) {
+ updatePrintAttributesFromCapabilities(newCapab);
+ }
+
+ final boolean updateNeeded = ((capabChanged && hasCapab && isActive)
+ || (becameActive && hasCapab) || (isActive && gotCapab));
+
+ if (updateNeeded && canUpdateDocument()) {
+ updateDocument(true, false);
+ }
+
+ updateOptionsUi();
+ }
+
+ private boolean capabilitiesChanged(PrinterCapabilitiesInfo oldCapabilities,
+ PrinterCapabilitiesInfo newCapabilities) {
+ if (oldCapabilities == null) {
+ if (newCapabilities != null) {
+ return true;
+ }
+ } else if (!oldCapabilities.equals(newCapabilities)) {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private final class MyOnItemSelectedListener implements AdapterView.OnItemSelectedListener {
+ @Override
+ public void onItemSelected(AdapterView<?> spinner, View view, int position, long id) {
+ if (spinner == mDestinationSpinner) {
+ if (position == AdapterView.INVALID_POSITION) {
+ return;
+ }
+
+ if (id == DEST_ADAPTER_ITEM_ID_ALL_PRINTERS) {
+ startSelectPrinterActivity();
+ return;
+ }
+
+ PrinterInfo currentPrinter = getCurrentPrinter();
+
+ // Why on earth item selected is called if no selection changed.
+ if (mOldCurrentPrinter == currentPrinter) {
+ return;
+ }
+ mOldCurrentPrinter = currentPrinter;
+
+ PrinterHolder printerHolder = mDestinationSpinnerAdapter.getPrinterHolder(
+ currentPrinter.getId());
+ if (!printerHolder.removed) {
+ mDestinationSpinnerAdapter.pruneRemovedPrinters();
+ ensurePreviewUiShown();
+ }
+
+ mPrintJob.setPrinterId(currentPrinter.getId());
+ mPrintJob.setPrinterName(currentPrinter.getName());
+
+ mPrinterRegistry.setTrackedPrinter(currentPrinter.getId());
+
+ PrinterCapabilitiesInfo capabilities = currentPrinter.getCapabilities();
+ if (capabilities != null) {
+ updatePrintAttributesFromCapabilities(capabilities);
+ }
+
+ mPrinterAvailabilityDetector.updatePrinter(currentPrinter);
+ } else if (spinner == mMediaSizeSpinner) {
+ SpinnerItem<MediaSize> mediaItem = mMediaSizeSpinnerAdapter.getItem(position);
+ if (mOrientationSpinner.getSelectedItemPosition() == 0) {
+ mPrintJob.getAttributes().setMediaSize(mediaItem.value.asPortrait());
+ } else {
+ mPrintJob.getAttributes().setMediaSize(mediaItem.value.asLandscape());
+ }
+ } else if (spinner == mColorModeSpinner) {
+ SpinnerItem<Integer> colorModeItem = mColorModeSpinnerAdapter.getItem(position);
+ mPrintJob.getAttributes().setColorMode(colorModeItem.value);
+ } else if (spinner == mOrientationSpinner) {
+ SpinnerItem<Integer> orientationItem = mOrientationSpinnerAdapter.getItem(position);
+ PrintAttributes attributes = mPrintJob.getAttributes();
+ if (mMediaSizeSpinner.getSelectedItem() != null) {
+ if (orientationItem.value == ORIENTATION_PORTRAIT) {
+ attributes.copyFrom(attributes.asPortrait());
+ } else {
+ attributes.copyFrom(attributes.asLandscape());
+ }
+ }
+ }
+
+ if (canUpdateDocument()) {
+ updateDocument(true, false);
+ }
+
+ updateOptionsUi();
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ /* do nothing*/
+ }
+ }
+
+ private boolean canUpdateDocument() {
+ if (mPrintedDocument.isDestroyed()) {
+ return false;
+ }
+
+ if (hasErrors()) {
+ return false;
+ }
+
+ PrintAttributes attributes = mPrintJob.getAttributes();
+
+ final int colorMode = attributes.getColorMode();
+ if (colorMode != PrintAttributes.COLOR_MODE_COLOR
+ && colorMode != PrintAttributes.COLOR_MODE_MONOCHROME) {
+ return false;
+ }
+ if (attributes.getMediaSize() == null) {
+ return false;
+ }
+ if (attributes.getMinMargins() == null) {
+ return false;
+ }
+ if (attributes.getResolution() == null) {
+ return false;
+ }
+
+ PrinterInfo currentPrinter = getCurrentPrinter();
+ if (currentPrinter == null) {
+ return false;
+ }
+ PrinterCapabilitiesInfo capabilities = currentPrinter.getCapabilities();
+ if (capabilities == null) {
+ return false;
+ }
+ if (currentPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private final class SelectAllOnFocusListener implements OnFocusChangeListener {
+ @Override
+ public void onFocusChange(View view, boolean hasFocus) {
+ EditText editText = (EditText) view;
+ if (!TextUtils.isEmpty(editText.getText())) {
+ editText.setSelection(editText.getText().length());
+ }
+ }
+ }
+
+ private final class RangeTextWatcher implements TextWatcher {
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ /* do nothing */
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ /* do nothing */
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ final boolean hadErrors = hasErrors();
+
+ String text = editable.toString();
+
+ if (TextUtils.isEmpty(text)) {
+ mPageRangeEditText.setError("");
+ updateOptionsUi();
+ return;
+ }
+
+ String escapedText = PATTERN_ESCAPE_SPECIAL_CHARS.matcher(text).replaceAll("////");
+ if (!PATTERN_PAGE_RANGE.matcher(escapedText).matches()) {
+ mPageRangeEditText.setError("");
+ updateOptionsUi();
+ return;
+ }
+
+ PrintDocumentInfo info = mPrintedDocument.getDocumentInfo().info;
+ final int pageCount = (info != null) ? info.getPageCount() : 0;
+
+ // The range
+ Matcher matcher = PATTERN_DIGITS.matcher(text);
+ while (matcher.find()) {
+ String numericString = text.substring(matcher.start(), matcher.end()).trim();
+ if (TextUtils.isEmpty(numericString)) {
+ continue;
+ }
+ final int pageIndex = Integer.parseInt(numericString);
+ if (pageIndex < 1 || pageIndex > pageCount) {
+ mPageRangeEditText.setError("");
+ updateOptionsUi();
+ return;
+ }
+ }
+
+ // We intentionally do not catch the case of the from page being
+ // greater than the to page. When computing the requested pages
+ // we just swap them if necessary.
+
+ // Keep the print job up to date with the selected pages if we
+ // know how many pages are there in the document.
+ mRequestedPages = computeRequestedPages();
+
+ mPageRangeEditText.setError(null);
+ mPrintButton.setEnabled(true);
+ updateOptionsUi();
+
+ if (hadErrors && !hasErrors()) {
+ updateOptionsUi();
+ }
+ }
+ }
+
+ private final class EditTextWatcher implements TextWatcher {
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ /* do nothing */
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ /* do nothing */
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ final boolean hadErrors = hasErrors();
+
+ if (editable.length() == 0) {
+ mCopiesEditText.setError("");
+ updateOptionsUi();
+ return;
+ }
+
+ int copies = 0;
+ try {
+ copies = Integer.parseInt(editable.toString());
+ } catch (NumberFormatException nfe) {
+ /* ignore */
+ }
+
+ if (copies < MIN_COPIES) {
+ mCopiesEditText.setError("");
+ updateOptionsUi();
+ return;
+ }
+
+ mPrintJob.setCopies(copies);
+
+ mCopiesEditText.setError(null);
+
+ updateOptionsUi();
+
+ if (hadErrors && canUpdateDocument()) {
+ updateDocument(true, false);
+ }
+ }
+ }
+
+ private final class ProgressMessageController implements Runnable {
+ private static final long PROGRESS_TIMEOUT_MILLIS = 1000;
+
+ private final Handler mHandler;
+
+ private boolean mPosted;
+
+ public ProgressMessageController(Context context) {
+ mHandler = new Handler(context.getMainLooper(), null, false);
+ }
+
+ public void post() {
+ if (mPosted) {
+ return;
+ }
+ mPosted = true;
+ mHandler.postDelayed(this, PROGRESS_TIMEOUT_MILLIS);
+ }
+
+ public void cancel() {
+ if (!mPosted) {
+ return;
+ }
+ mPosted = false;
+ mHandler.removeCallbacks(this);
+ }
+
+ @Override
+ public void run() {
+ ensureProgressUiShown();
+ }
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintErrorFragment.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintErrorFragment.java
new file mode 100644
index 0000000..b708356
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintErrorFragment.java
@@ -0,0 +1,103 @@
+/*
+ * 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.printspooler.ui;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.printspooler.R;
+
+/**
+ * Fragment for showing an error UI.
+ */
+public final class PrintErrorFragment extends Fragment {
+ public static final int ACTION_NONE = 0;
+ public static final int ACTION_RETRY = 1;
+ public static final int ACTION_CONFIRM = 2;
+
+ public interface OnActionListener {
+ public void onActionPerformed();
+ }
+
+ private static final String EXTRA_ERROR_MESSAGE = "EXTRA_ERROR_MESSAGE";
+ private static final String EXTRA_ACTION = "EXTRA_ACTION";
+
+ public static PrintErrorFragment newInstance(CharSequence errorMessage, int action) {
+ PrintErrorFragment instance = new PrintErrorFragment();
+ Bundle arguments = new Bundle();
+ arguments.putCharSequence(EXTRA_ERROR_MESSAGE, errorMessage);
+ arguments.putInt(EXTRA_ACTION, action);
+ instance.setArguments(arguments);
+ return instance;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup root,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.print_error_fragment, root, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ Bundle arguments = getArguments();
+
+ CharSequence error = arguments.getString(EXTRA_ERROR_MESSAGE);
+ if (!TextUtils.isEmpty(error)) {
+ TextView message = (TextView) view.findViewById(R.id.message);
+ message.setText(error);
+ }
+
+ Button actionButton = (Button) view.findViewById(R.id.action_button);
+
+ final int action = getArguments().getInt(EXTRA_ACTION);
+ switch (action) {
+ case ACTION_RETRY: {
+ actionButton.setVisibility(View.VISIBLE);
+ actionButton.setText(R.string.print_error_retry);
+ } break;
+
+ case ACTION_CONFIRM: {
+ actionButton.setVisibility(View.VISIBLE);
+ actionButton.setText(android.R.string.ok);
+ } break;
+
+ case ACTION_NONE: {
+ actionButton.setVisibility(View.GONE);
+ } break;
+ }
+
+ actionButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Activity activity = getActivity();
+ if (activity instanceof OnActionListener) {
+ ((OnActionListener) getActivity()).onActionPerformed();
+ }
+ }
+ });
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewFragment.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewFragment.java
new file mode 100644
index 0000000..d68a6aa
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewFragment.java
@@ -0,0 +1,12 @@
+package com.android.printspooler.ui;
+
+import android.app.Fragment;
+
+public class PrintPreviewFragment extends Fragment {
+
+ public static PrintPreviewFragment newInstance() {
+ return new PrintPreviewFragment();
+ }
+
+ // TODO: Implement
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintProgressFragment.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintProgressFragment.java
new file mode 100644
index 0000000..96aa153d
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintProgressFragment.java
@@ -0,0 +1,69 @@
+/*
+ * 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.printspooler.ui;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+
+import android.widget.TextView;
+import com.android.printspooler.R;
+
+/**
+ * Fragment for showing a work in progress UI.
+ */
+public final class PrintProgressFragment extends Fragment {
+
+ public interface OnCancelRequestListener {
+ public void onCancelRequest();
+ }
+
+ public static PrintProgressFragment newInstance() {
+ return new PrintProgressFragment();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup root,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.print_progress_fragment, root, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ final Button cancelButton = (Button) view.findViewById(R.id.cancel_button);
+ final TextView message = (TextView) view.findViewById(R.id.message);
+
+ cancelButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Activity activity = getActivity();
+ if (activity instanceof OnCancelRequestListener) {
+ ((OnCancelRequestListener) getActivity()).onCancelRequest();
+ }
+ cancelButton.setVisibility(View.GONE);
+ message.setVisibility(View.VISIBLE);
+ }
+ });
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
new file mode 100644
index 0000000..7816d66
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
@@ -0,0 +1,168 @@
+/*
+ * 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.printspooler.ui;
+
+import android.app.Activity;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.Loader;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import com.android.internal.os.SomeArgs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PrinterRegistry {
+
+ private static final int LOADER_ID_PRINTERS_LOADER = 1;
+
+ private final Activity mActivity;
+
+ private final List<PrinterInfo> mPrinters = new ArrayList<>();
+
+ private final Runnable mReadyCallback;
+
+ private final Handler mHandler;
+
+ private boolean mReady;
+
+ private OnPrintersChangeListener mOnPrintersChangeListener;
+
+ public interface OnPrintersChangeListener {
+ public void onPrintersChanged(List<PrinterInfo> printers);
+ public void onPrintersInvalid();
+ }
+
+ public PrinterRegistry(Activity activity, Runnable readyCallback) {
+ mActivity = activity;
+ mReadyCallback = readyCallback;
+ mHandler = new MyHandler(activity.getMainLooper());
+ activity.getLoaderManager().initLoader(LOADER_ID_PRINTERS_LOADER,
+ null, mLoaderCallbacks);
+ }
+
+ public void setOnPrintersChangeListener(OnPrintersChangeListener listener) {
+ mOnPrintersChangeListener = listener;
+ }
+
+ public List<PrinterInfo> getPrinters() {
+ return mPrinters;
+ }
+
+ public void addHistoricalPrinter(PrinterInfo printer) {
+ getPrinterProvider().addHistoricalPrinter(printer);
+ }
+
+ public void forgetFavoritePrinter(PrinterId printerId) {
+ getPrinterProvider().forgetFavoritePrinter(printerId);
+ }
+
+ public boolean isFavoritePrinter(PrinterId printerId) {
+ return getPrinterProvider().isFavoritePrinter(printerId);
+ }
+
+ public void setTrackedPrinter(PrinterId printerId) {
+ getPrinterProvider().setTrackedPrinter(printerId);
+ }
+
+ private FusedPrintersProvider getPrinterProvider() {
+ Loader<?> loader = mActivity.getLoaderManager().getLoader(LOADER_ID_PRINTERS_LOADER);
+ return (FusedPrintersProvider) loader;
+ }
+
+ private final LoaderCallbacks<List<PrinterInfo>> mLoaderCallbacks =
+ new LoaderCallbacks<List<PrinterInfo>>() {
+ @Override
+ public void onLoaderReset(Loader<List<PrinterInfo>> loader) {
+ if (loader.getId() == LOADER_ID_PRINTERS_LOADER) {
+ mPrinters.clear();
+ if (mOnPrintersChangeListener != null) {
+ // Post a message as we are in onLoadFinished and certain operations
+ // are not allowed in this callback, such as fragment transactions.
+ // Clients should not handle this explicitly.
+ mHandler.obtainMessage(MyHandler.MSG_PRINTERS_INVALID,
+ mOnPrintersChangeListener).sendToTarget();
+ }
+ }
+ }
+
+ // LoaderCallbacks#onLoadFinished
+ @Override
+ public void onLoadFinished(Loader<List<PrinterInfo>> loader, List<PrinterInfo> printers) {
+ if (loader.getId() == LOADER_ID_PRINTERS_LOADER) {
+ mPrinters.clear();
+ mPrinters.addAll(printers);
+ if (mOnPrintersChangeListener != null) {
+ // Post a message as we are in onLoadFinished and certain operations
+ // are not allowed in this callback, such as fragment transactions.
+ // Clients should not handle this explicitly.
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = mOnPrintersChangeListener;
+ args.arg2 = printers;
+ mHandler.obtainMessage(MyHandler.MSG_PRINTERS_CHANGED, args).sendToTarget();
+ }
+ if (!mReady) {
+ mReady = true;
+ if (mReadyCallback != null) {
+ mReadyCallback.run();
+ }
+ }
+ }
+ }
+
+ // LoaderCallbacks#onCreateLoader
+ @Override
+ public Loader<List<PrinterInfo>> onCreateLoader(int id, Bundle args) {
+ if (id == LOADER_ID_PRINTERS_LOADER) {
+ return new FusedPrintersProvider(mActivity);
+ }
+ return null;
+ }
+ };
+
+ private static final class MyHandler extends Handler {
+ public static final int MSG_PRINTERS_CHANGED = 0;
+ public static final int MSG_PRINTERS_INVALID = 1;
+
+ public MyHandler(Looper looper) {
+ super(looper, null , false);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_PRINTERS_CHANGED: {
+ SomeArgs args = (SomeArgs) message.obj;
+ OnPrintersChangeListener callback = (OnPrintersChangeListener) args.arg1;
+ List<PrinterInfo> printers = (List<PrinterInfo>) args.arg2;
+ args.recycle();
+ callback.onPrintersChanged(printers);
+ } break;
+
+ case MSG_PRINTERS_INVALID: {
+ OnPrintersChangeListener callback = (OnPrintersChangeListener) message.obj;
+ callback.onPrintersInvalid();
+ } break;
+ }
+ }
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
similarity index 73%
rename from packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
rename to packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index fe5920c..7715579 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.printspooler;
+package com.android.printspooler.ui;
import android.app.Activity;
import android.app.AlertDialog;
@@ -22,13 +22,11 @@
import android.app.DialogFragment;
import android.app.Fragment;
import android.app.FragmentTransaction;
-import android.app.LoaderManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.Loader;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -48,9 +46,7 @@
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
import android.view.Menu;
-import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -66,63 +62,60 @@
import android.widget.SearchView;
import android.widget.TextView;
+import com.android.printspooler.R;
+
import java.util.ArrayList;
import java.util.List;
/**
- * This is a fragment for selecting a printer.
+ * This is an activity for selecting a printer.
*/
-public final class SelectPrinterFragment extends Fragment {
+public final class SelectPrinterActivity extends Activity {
private static final String LOG_TAG = "SelectPrinterFragment";
- private static final int LOADER_ID_PRINTERS_LOADER = 1;
+ public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
- private static final String FRAGMRNT_TAG_ADD_PRINTER_DIALOG =
- "FRAGMRNT_TAG_ADD_PRINTER_DIALOG";
+ private static final String FRAGMENT_TAG_ADD_PRINTER_DIALOG =
+ "FRAGMENT_TAG_ADD_PRINTER_DIALOG";
- private static final String FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS =
- "FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS";
+ private static final String FRAGMENT_ARGUMENT_PRINT_SERVICE_INFOS =
+ "FRAGMENT_ARGUMENT_PRINT_SERVICE_INFOS";
private static final String EXTRA_PRINTER_ID = "EXTRA_PRINTER_ID";
private final ArrayList<PrintServiceInfo> mAddPrinterServices =
- new ArrayList<PrintServiceInfo>();
+ new ArrayList<>();
+
+ private PrinterRegistry mPrinterRegistry;
private ListView mListView;
private AnnounceFilterResult mAnnounceFilterResult;
- public static interface OnPrinterSelectedListener {
- public void onPrinterSelected(PrinterId printerId);
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setHasOptionsMenu(true);
- getActivity().getActionBar().setIcon(R.drawable.ic_menu_print);
- }
+ getActionBar().setIcon(R.drawable.ic_menu_print);
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View content = inflater.inflate(R.layout.select_printer_fragment, container, false);
+ setContentView(R.layout.select_printer_activity);
+
+ mPrinterRegistry = new PrinterRegistry(this, null);
// Hook up the list view.
- mListView = (ListView) content.findViewById(android.R.id.list);
+ mListView = (ListView) findViewById(android.R.id.list);
final DestinationAdapter adapter = new DestinationAdapter();
adapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
- if (!getActivity().isFinishing() && adapter.getCount() <= 0) {
+ if (!isFinishing() && adapter.getCount() <= 0) {
updateEmptyView(adapter);
}
}
@Override
public void onInvalidated() {
- if (!getActivity().isFinishing()) {
+ if (!isFinishing()) {
updateEmptyView(adapter);
}
}
@@ -135,26 +128,20 @@
if (!((DestinationAdapter) mListView.getAdapter()).isActionable(position)) {
return;
}
+
PrinterInfo printer = (PrinterInfo) mListView.getAdapter().getItem(position);
- Activity activity = getActivity();
- if (activity instanceof OnPrinterSelectedListener) {
- ((OnPrinterSelectedListener) activity).onPrinterSelected(printer.getId());
- } else {
- throw new IllegalStateException("the host activity must implement"
- + " OnPrinterSelectedListener");
- }
+ onPrinterSelected(printer.getId());
}
});
registerForContextMenu(mListView);
-
- return content;
}
@Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- super.onCreateOptionsMenu(menu, inflater);
- inflater.inflate(R.menu.select_printer_activity, menu);
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+
+ getMenuInflater().inflate(R.menu.select_printer_activity, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
@@ -173,16 +160,15 @@
searchView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View view) {
- if (AccessibilityManager.getInstance(getActivity()).isEnabled()) {
+ if (AccessibilityManager.getInstance(SelectPrinterActivity.this).isEnabled()) {
view.announceForAccessibility(getString(
R.string.print_search_box_shown_utterance));
}
}
@Override
public void onViewDetachedFromWindow(View view) {
- Activity activity = getActivity();
- if (activity != null && !activity.isFinishing()
- && AccessibilityManager.getInstance(activity).isEnabled()) {
+ if (!isFinishing() && AccessibilityManager.getInstance(
+ SelectPrinterActivity.this).isEnabled()) {
view.announceForAccessibility(getString(
R.string.print_search_box_hidden_utterance));
}
@@ -192,6 +178,8 @@
if (mAddPrinterServices.isEmpty()) {
menu.removeItem(R.id.action_add_printer);
}
+
+ return true;
}
@Override
@@ -212,9 +200,7 @@
}
// Add the forget menu item if applicable.
- FusedPrintersProvider provider = (FusedPrintersProvider) (Loader<?>)
- getLoaderManager().getLoader(LOADER_ID_PRINTERS_LOADER);
- if (provider.isFavoritePrinter(printer.getId())) {
+ if (mPrinterRegistry.isFavoritePrinter(printer.getId())) {
MenuItem forgetItem = menu.add(Menu.NONE, R.string.print_forget_printer,
Menu.NONE, R.string.print_forget_printer);
Intent intent = new Intent();
@@ -228,23 +214,13 @@
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.string.print_select_printer: {
- PrinterId printerId = (PrinterId) item.getIntent().getParcelableExtra(
- EXTRA_PRINTER_ID);
- Activity activity = getActivity();
- if (activity instanceof OnPrinterSelectedListener) {
- ((OnPrinterSelectedListener) activity).onPrinterSelected(printerId);
- } else {
- throw new IllegalStateException("the host activity must implement"
- + " OnPrinterSelectedListener");
- }
+ PrinterId printerId = item.getIntent().getParcelableExtra(EXTRA_PRINTER_ID);
+ onPrinterSelected(printerId);
} return true;
case R.string.print_forget_printer: {
- PrinterId printerId = (PrinterId) item.getIntent().getParcelableExtra(
- EXTRA_PRINTER_ID);
- FusedPrintersProvider provider = (FusedPrintersProvider) (Loader<?>)
- getLoaderManager().getLoader(LOADER_ID_PRINTERS_LOADER);
- provider.forgetFavoritePrinter(printerId);
+ PrinterId printerId = item.getIntent().getParcelableExtra(EXTRA_PRINTER_ID);
+ mPrinterRegistry.forgetFavoritePrinter(printerId);
} return true;
}
return false;
@@ -252,9 +228,9 @@
@Override
public void onResume() {
- updateAddPrintersAdapter();
- getActivity().invalidateOptionsMenu();
super.onResume();
+ updateServicesWithAddPrinterActivity();
+ invalidateOptionsMenu();
}
@Override
@@ -274,12 +250,18 @@
return super.onOptionsItemSelected(item);
}
- private void updateAddPrintersAdapter() {
+ private void onPrinterSelected(PrinterId printerId) {
+ Intent intent = new Intent();
+ intent.putExtra(INTENT_EXTRA_PRINTER_ID, printerId);
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+
+ private void updateServicesWithAddPrinterActivity() {
mAddPrinterServices.clear();
// Get all enabled print services.
- PrintManager printManager = (PrintManager) getActivity()
- .getSystemService(Context.PRINT_SERVICE);
+ PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE);
List<PrintServiceInfo> enabledServices = printManager.getEnabledPrintServices();
// No enabled print services - done.
@@ -292,7 +274,7 @@
for (int i = 0; i < enabledServiceCount; i++) {
PrintServiceInfo enabledService = enabledServices.get(i);
- // No add printers activity declared - done.
+ // No add printers activity declared - next.
if (TextUtils.isEmpty(enabledService.getAddPrintersActivityName())) {
continue;
}
@@ -304,15 +286,14 @@
.setComponent(addPrintersComponentName);
// The add printers activity is valid - add it.
- PackageManager pm = getActivity().getPackageManager();
+ PackageManager pm = getPackageManager();
List<ResolveInfo> resolvedActivities = pm.queryIntentActivities(addPritnersIntent, 0);
if (!resolvedActivities.isEmpty()) {
// The activity is a component name, therefore it is one or none.
ActivityInfo activityInfo = resolvedActivities.get(0).activityInfo;
if (activityInfo.exported
&& (activityInfo.permission == null
- || pm.checkPermission(activityInfo.permission,
- getActivity().getPackageName())
+ || pm.checkPermission(activityInfo.permission, getPackageName())
== PackageManager.PERMISSION_GRANTED)) {
mAddPrinterServices.add(enabledService);
}
@@ -323,26 +304,26 @@
private void showAddPrinterSelectionDialog() {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
Fragment oldFragment = getFragmentManager().findFragmentByTag(
- FRAGMRNT_TAG_ADD_PRINTER_DIALOG);
+ FRAGMENT_TAG_ADD_PRINTER_DIALOG);
if (oldFragment != null) {
transaction.remove(oldFragment);
}
AddPrinterAlertDialogFragment newFragment = new AddPrinterAlertDialogFragment();
Bundle arguments = new Bundle();
- arguments.putParcelableArrayList(FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS,
+ arguments.putParcelableArrayList(FRAGMENT_ARGUMENT_PRINT_SERVICE_INFOS,
mAddPrinterServices);
newFragment.setArguments(arguments);
- transaction.add(newFragment, FRAGMRNT_TAG_ADD_PRINTER_DIALOG);
+ transaction.add(newFragment, FRAGMENT_TAG_ADD_PRINTER_DIALOG);
transaction.commit();
}
public void updateEmptyView(DestinationAdapter adapter) {
if (mListView.getEmptyView() == null) {
- View emptyView = getActivity().findViewById(R.id.empty_print_state);
+ View emptyView = findViewById(R.id.empty_print_state);
mListView.setEmptyView(emptyView);
}
- TextView titleView = (TextView) getActivity().findViewById(R.id.title);
- View progressBar = getActivity().findViewById(R.id.progress_bar);
+ TextView titleView = (TextView) findViewById(R.id.title);
+ View progressBar = findViewById(R.id.progress_bar);
if (adapter.getUnfilteredCount() <= 0) {
titleView.setText(R.string.print_searching_for_printers);
progressBar.setVisibility(View.VISIBLE);
@@ -353,7 +334,7 @@
}
private void announceSearchResultIfNeeded() {
- if (AccessibilityManager.getInstance(getActivity()).isEnabled()) {
+ if (AccessibilityManager.getInstance(this).isEnabled()) {
if (mAnnounceFilterResult == null) {
mAnnounceFilterResult = new AnnounceFilterResult();
}
@@ -372,9 +353,9 @@
.setTitle(R.string.choose_print_service);
final List<PrintServiceInfo> printServices = (List<PrintServiceInfo>) (List<?>)
- getArguments().getParcelableArrayList(FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS);
+ getArguments().getParcelableArrayList(FRAGMENT_ARGUMENT_PRINT_SERVICE_INFOS);
- final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
+ final ArrayAdapter<String> adapter = new ArrayAdapter<>(
getActivity(), android.R.layout.simple_list_item_1);
final int printServiceCount = printServices.size();
for (int i = 0; i < printServiceCount; i++) {
@@ -382,32 +363,33 @@
adapter.add(printService.getResolveInfo().loadLabel(
getActivity().getPackageManager()).toString());
}
+
final String searchUri = Settings.Secure.getString(getActivity().getContentResolver(),
Settings.Secure.PRINT_SERVICE_SEARCH_URI);
- final Intent marketIntent;
+ final Intent viewIntent;
if (!TextUtils.isEmpty(searchUri)) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri));
if (getActivity().getPackageManager().resolveActivity(intent, 0) != null) {
- marketIntent = intent;
+ viewIntent = intent;
mAddPrintServiceItem = getString(R.string.add_print_service_label);
adapter.add(mAddPrintServiceItem);
} else {
- marketIntent = null;
+ viewIntent = null;
}
} else {
- marketIntent = null;
+ viewIntent = null;
}
builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String item = adapter.getItem(which);
- if (item == mAddPrintServiceItem) {
+ if (item.equals(mAddPrintServiceItem)) {
try {
- startActivity(marketIntent);
- } catch (ActivityNotFoundException anfe) {
- Log.w(LOG_TAG, "Couldn't start add printer activity", anfe);
- }
+ startActivity(viewIntent);
+ } catch (ActivityNotFoundException anfe) {
+ Log.w(LOG_TAG, "Couldn't start add printer activity", anfe);
+ }
} else {
PrintServiceInfo printService = printServices.get(which);
ComponentName componentName = new ComponentName(
@@ -418,7 +400,7 @@
try {
startActivity(intent);
} catch (ActivityNotFoundException anfe) {
- Log.w(LOG_TAG, "Couldn't start settings activity", anfe);
+ Log.w(LOG_TAG, "Couldn't start add printer activity", anfe);
}
}
}
@@ -428,19 +410,41 @@
}
}
- private final class DestinationAdapter extends BaseAdapter
- implements LoaderManager.LoaderCallbacks<List<PrinterInfo>>, Filterable {
+ private final class DestinationAdapter extends BaseAdapter implements Filterable {
private final Object mLock = new Object();
- private final List<PrinterInfo> mPrinters = new ArrayList<PrinterInfo>();
+ private final List<PrinterInfo> mPrinters = new ArrayList<>();
- private final List<PrinterInfo> mFilteredPrinters = new ArrayList<PrinterInfo>();
+ private final List<PrinterInfo> mFilteredPrinters = new ArrayList<>();
private CharSequence mLastSearchString;
public DestinationAdapter() {
- getLoaderManager().initLoader(LOADER_ID_PRINTERS_LOADER, null, this);
+ mPrinterRegistry.setOnPrintersChangeListener(new PrinterRegistry.OnPrintersChangeListener() {
+ @Override
+ public void onPrintersChanged(List<PrinterInfo> printers) {
+ synchronized (mLock) {
+ mPrinters.clear();
+ mPrinters.addAll(printers);
+ mFilteredPrinters.clear();
+ mFilteredPrinters.addAll(printers);
+ if (!TextUtils.isEmpty(mLastSearchString)) {
+ getFilter().filter(mLastSearchString);
+ }
+ }
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public void onPrintersInvalid() {
+ synchronized (mLock) {
+ mPrinters.clear();
+ mFilteredPrinters.clear();
+ }
+ notifyDataSetInvalidated();
+ }
+ });
}
@Override
@@ -453,7 +457,7 @@
return null;
}
FilterResults results = new FilterResults();
- List<PrinterInfo> filteredPrinters = new ArrayList<PrinterInfo>();
+ List<PrinterInfo> filteredPrinters = new ArrayList<>();
String constraintLowerCase = constraint.toString().toLowerCase();
final int printerCount = mPrinters.size();
for (int i = 0; i < printerCount; i++) {
@@ -518,28 +522,27 @@
}
@Override
- public View getDropDownView(int position, View convertView,
- ViewGroup parent) {
+ public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
- convertView = getActivity().getLayoutInflater().inflate(
+ convertView = getLayoutInflater().inflate(
R.layout.printer_list_item, parent, false);
}
convertView.setEnabled(isActionable(position));
- CharSequence title = null;
+ PrinterInfo printer = (PrinterInfo) getItem(position);
+
+ CharSequence title = printer.getName();
CharSequence subtitle = null;
Drawable icon = null;
- PrinterInfo printer = (PrinterInfo) getItem(position);
- title = printer.getName();
try {
- PackageManager pm = getActivity().getPackageManager();
+ PackageManager pm = getPackageManager();
PackageInfo packageInfo = pm.getPackageInfo(printer.getId()
.getServiceName().getPackageName(), 0);
subtitle = packageInfo.applicationInfo.loadLabel(pm);
@@ -576,38 +579,6 @@
PrinterInfo printer = (PrinterInfo) getItem(position);
return printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE;
}
-
- @Override
- public Loader<List<PrinterInfo>> onCreateLoader(int id, Bundle args) {
- if (id == LOADER_ID_PRINTERS_LOADER) {
- return new FusedPrintersProvider(getActivity());
- }
- return null;
- }
-
- @Override
- public void onLoadFinished(Loader<List<PrinterInfo>> loader,
- List<PrinterInfo> printers) {
- synchronized (mLock) {
- mPrinters.clear();
- mPrinters.addAll(printers);
- mFilteredPrinters.clear();
- mFilteredPrinters.addAll(printers);
- if (!TextUtils.isEmpty(mLastSearchString)) {
- getFilter().filter(mLastSearchString);
- }
- }
- notifyDataSetChanged();
- }
-
- @Override
- public void onLoaderReset(Loader<List<PrinterInfo>> loader) {
- synchronized (mLock) {
- mPrinters.clear();
- mFilteredPrinters.clear();
- }
- notifyDataSetInvalidated();
- }
}
private final class AnnounceFilterResult implements Runnable {
@@ -629,7 +600,7 @@
if (count <= 0) {
text = getString(R.string.print_no_printers);
} else {
- text = getActivity().getResources().getQuantityString(
+ text = getResources().getQuantityString(
R.plurals.print_search_result_count_utterance, count, count);
}
mListView.announceForAccessibility(text);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/MediaSizeUtils.java b/packages/PrintSpooler/src/com/android/printspooler/util/MediaSizeUtils.java
similarity index 95%
rename from packages/PrintSpooler/src/com/android/printspooler/MediaSizeUtils.java
rename to packages/PrintSpooler/src/com/android/printspooler/util/MediaSizeUtils.java
index ac27562..912ee1d 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/MediaSizeUtils.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/util/MediaSizeUtils.java
@@ -14,22 +14,28 @@
* limitations under the License.
*/
-package com.android.printspooler;
+package com.android.printspooler.util;
import android.content.Context;
import android.print.PrintAttributes.MediaSize;
import android.util.ArrayMap;
+import com.android.printspooler.R;
+
import java.util.Comparator;
import java.util.Map;
/**
* Utility functions and classes for dealing with media sizes.
*/
-public class MediaSizeUtils {
+public final class MediaSizeUtils {
private static Map<MediaSize, String> sMediaSizeToStandardMap;
+ private MediaSizeUtils() {
+ /* do nothing - hide constructor */
+ }
+
/**
* Gets the default media size for the current locale.
*
diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java b/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java
new file mode 100644
index 0000000..33b294f
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java
@@ -0,0 +1,159 @@
+/*
+ * 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.printspooler.util;
+
+import android.print.PageRange;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * This class contains utility functions for working with page ranges.
+ */
+public final class PageRangeUtils {
+
+ private static final PageRange[] ALL_PAGES_RANGE = new PageRange[] {PageRange.ALL_PAGES};
+
+ private static final Comparator<PageRange> sComparator = new Comparator<PageRange>() {
+ @Override
+ public int compare(PageRange lhs, PageRange rhs) {
+ return lhs.getStart() - rhs.getStart();
+ }
+ };
+
+ private PageRangeUtils() {
+ /* do nothing - hide constructor */
+ }
+
+ /**
+ * Checks whether one page range array contains another one.
+ *
+ * @param ourRanges The container page ranges.
+ * @param otherRanges The contained page ranges.
+ * @return Whether the container page ranges contains the contained ones.
+ */
+ public static boolean contains(PageRange[] ourRanges, PageRange[] otherRanges) {
+ if (ourRanges == null || otherRanges == null) {
+ return false;
+ }
+
+ if (Arrays.equals(ourRanges, ALL_PAGES_RANGE)) {
+ return true;
+ }
+
+ ourRanges = normalize(ourRanges);
+ otherRanges = normalize(otherRanges);
+
+ // Note that the code below relies on the ranges being normalized
+ // which is they contain monotonically increasing non-intersecting
+ // sub-ranges whose start is less that or equal to the end.
+ int otherRangeIdx = 0;
+ final int ourRangeCount = ourRanges.length;
+ final int otherRangeCount = otherRanges.length;
+ for (int ourRangeIdx = 0; ourRangeIdx < ourRangeCount; ourRangeIdx++) {
+ PageRange ourRange = ourRanges[ourRangeIdx];
+ for (; otherRangeIdx < otherRangeCount; otherRangeIdx++) {
+ PageRange otherRange = otherRanges[otherRangeIdx];
+ if (otherRange.getStart() > ourRange.getEnd()) {
+ break;
+ }
+ if (otherRange.getStart() < ourRange.getStart()
+ || otherRange.getEnd() > ourRange.getEnd()) {
+ return false;
+ }
+ }
+ }
+ if (otherRangeIdx < otherRangeCount) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Normalizes a page range, which is the resulting page ranges are
+ * non-overlapping with the start lesser than or equal to the end
+ * and ordered in an ascending order.
+ *
+ * @param pageRanges The page ranges to normalize.
+ * @return The normalized page ranges.
+ */
+ public static PageRange[] normalize(PageRange[] pageRanges) {
+ if (pageRanges == null) {
+ return null;
+ }
+ final int oldRangeCount = pageRanges.length;
+ if (oldRangeCount <= 1) {
+ return pageRanges;
+ }
+ Arrays.sort(pageRanges, sComparator);
+ int newRangeCount = 1;
+ for (int i = 0; i < oldRangeCount - 1; i++) {
+ newRangeCount++;
+ PageRange currentRange = pageRanges[i];
+ PageRange nextRange = pageRanges[i + 1];
+ if (currentRange.getEnd() + 1 >= nextRange.getStart()) {
+ newRangeCount--;
+ pageRanges[i] = null;
+ pageRanges[i + 1] = new PageRange(currentRange.getStart(),
+ Math.max(currentRange.getEnd(), nextRange.getEnd()));
+ }
+ }
+ if (newRangeCount == oldRangeCount) {
+ return pageRanges;
+ }
+ return Arrays.copyOfRange(pageRanges, oldRangeCount - newRangeCount,
+ oldRangeCount);
+ }
+
+ /**
+ * Offsets a the start and end of page ranges with the given value.
+ *
+ * @param pageRanges The page ranges to offset.
+ * @param offset The offset value.
+ */
+ public static void offset(PageRange[] pageRanges, int offset) {
+ if (offset == 0) {
+ return;
+ }
+ final int pageRangeCount = pageRanges.length;
+ for (int i = 0; i < pageRangeCount; i++) {
+ final int start = pageRanges[i].getStart() + offset;
+ final int end = pageRanges[i].getEnd() + offset;
+ pageRanges[i] = new PageRange(start, end);
+ }
+ }
+
+ /**
+ * Gets the number of pages in a normalized range array.
+ *
+ * @param pageRanges Normalized page ranges.
+ * @param layoutPageCount Page count after reported after layout pass.
+ * @return The page count in the ranges.
+ */
+ public static int getNormalizedPageCount(PageRange[] pageRanges, int layoutPageCount) {
+ int pageCount = 0;
+ final int pageRangeCount = pageRanges.length;
+ for (int i = 0; i < pageRangeCount; i++) {
+ PageRange pageRange = pageRanges[i];
+ if (PageRange.ALL_PAGES.equals(pageRange)) {
+ return layoutPageCount;
+ }
+ pageCount += pageRange.getEnd() - pageRange.getStart() + 1;
+ }
+ return pageCount;
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/PrintOptionUtils.java b/packages/PrintSpooler/src/com/android/printspooler/util/PrintOptionUtils.java
new file mode 100644
index 0000000..446952d
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/util/PrintOptionUtils.java
@@ -0,0 +1,56 @@
+/*
+ * 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.printspooler.util;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ServiceInfo;
+import android.print.PrintManager;
+import android.printservice.PrintServiceInfo;
+
+import java.util.List;
+
+public class PrintOptionUtils {
+
+ private PrintOptionUtils() {
+ /* ignore - hide constructor */
+ }
+
+ /**
+ * Gets the advanced options activity name for a print service.
+ *
+ * @param context Context for accessing system resources.
+ * @param serviceName The print service name.
+ * @return The advanced options activity name or null.
+ */
+ public static String getAdvancedOptionsActivityName(Context context,
+ ComponentName serviceName) {
+ PrintManager printManager = (PrintManager) context.getSystemService(
+ Context.PRINT_SERVICE);
+ List<PrintServiceInfo> printServices = printManager.getEnabledPrintServices();
+ final int printServiceCount = printServices.size();
+ for (int i = 0; i < printServiceCount; i ++) {
+ PrintServiceInfo printServiceInfo = printServices.get(i);
+ ServiceInfo serviceInfo = printServiceInfo.getResolveInfo().serviceInfo;
+ if (serviceInfo.name.equals(serviceName.getClassName())
+ && serviceInfo.packageName.equals(serviceName.getPackageName())) {
+ return printServiceInfo.getAdvancedOptionsActivityName();
+ }
+ }
+ return null;
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/ContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/ContentView.java
new file mode 100644
index 0000000..77ca541
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/ContentView.java
@@ -0,0 +1,338 @@
+/*
+ * 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.printspooler.widget;
+
+import android.content.Context;
+import android.support.v4.widget.ViewDragHelper;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.printspooler.R;
+
+/**
+ * This class is a layout manager for the print screen. It has a sliding
+ * area that contains the print options. If the sliding area is open the
+ * print options are visible and if it is closed a summary of the print
+ * job is shown. Under the sliding area there is a place for putting
+ * arbitrary content such as preview, error message, progress indicator,
+ * etc. The sliding area is covering the content holder under it when
+ * the former is opened.
+ */
+@SuppressWarnings("unused")
+public final class ContentView extends ViewGroup implements View.OnClickListener {
+ private static final int FIRST_POINTER_ID = 0;
+
+ private final ViewDragHelper mDragger;
+
+ private View mStaticContent;
+ private ViewGroup mSummaryContent;
+ private View mDynamicContent;
+
+ private View mDraggableContent;
+ private ViewGroup mMoreOptionsContainer;
+ private ViewGroup mOptionsContainer;
+
+ private View mEmbeddedContentContainer;
+
+ private View mExpandCollapseHandle;
+ private View mExpandCollapseIcon;
+
+ private int mClosedOptionsOffsetY;
+ private int mCurrentOptionsOffsetY;
+
+ private OptionsStateChangeListener mOptionsStateChangeListener;
+
+ private int mOldDraggableHeight;
+
+ public interface OptionsStateChangeListener {
+ public void onOptionsOpened();
+ public void onOptionsClosed();
+ }
+
+ public ContentView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mDragger = ViewDragHelper.create(this, new DragCallbacks());
+
+ // The options view is sliding under the static header but appears
+ // after it in the layout, so we will draw in opposite order.
+ setChildrenDrawingOrderEnabled(true);
+ }
+
+ public void setOptionsStateChangeListener(OptionsStateChangeListener listener) {
+ mOptionsStateChangeListener = listener;
+ }
+
+ private boolean isOptionsOpened() {
+ return mCurrentOptionsOffsetY == 0;
+ }
+
+ private boolean isOptionsClosed() {
+ return mCurrentOptionsOffsetY == mClosedOptionsOffsetY;
+ }
+
+ private void openOptions() {
+ if (isOptionsOpened()) {
+ return;
+ }
+ mDragger.smoothSlideViewTo(mDynamicContent, mDynamicContent.getLeft(),
+ getOpenedOptionsY());
+ invalidate();
+ }
+
+ private void closeOptions() {
+ if (isOptionsClosed()) {
+ return;
+ }
+ mDragger.smoothSlideViewTo(mDynamicContent, mDynamicContent.getLeft(),
+ getClosedOptionsY());
+ invalidate();
+ }
+
+ @Override
+ protected int getChildDrawingOrder(int childCount, int i) {
+ return childCount - i - 1;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ mStaticContent = findViewById(R.id.static_content);
+ mSummaryContent = (ViewGroup) findViewById(R.id.summary_content);
+ mDynamicContent = findViewById(R.id.dynamic_content);
+ mDraggableContent = findViewById(R.id.draggable_content);
+ mMoreOptionsContainer = (ViewGroup) findViewById(R.id.more_options_container);
+ mOptionsContainer = (ViewGroup) findViewById(R.id.options_container);
+ mEmbeddedContentContainer = findViewById(R.id.embedded_content_container);
+ mExpandCollapseIcon = findViewById(R.id.expand_collapse_icon);
+ mExpandCollapseHandle = findViewById(R.id.expand_collapse_handle);
+
+ mExpandCollapseIcon.setOnClickListener(this);
+ mExpandCollapseHandle.setOnClickListener(this);
+
+ // Make sure we start in a closed options state.
+ onDragProgress(1.0f);
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (view == mExpandCollapseHandle || view == mExpandCollapseIcon) {
+ if (isOptionsClosed()) {
+ openOptions();
+ } else if (isOptionsOpened()) {
+ closeOptions();
+ } // else in open/close progress do nothing.
+ }
+ }
+
+ @Override
+ public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+ /* do nothing */
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ mDragger.processTouchEvent(event);
+ return true;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+ return mDragger.shouldInterceptTouchEvent(event)
+ || super.onInterceptTouchEvent(event);
+ }
+
+ @Override
+ public void computeScroll() {
+ if (mDragger.continueSettling(true)) {
+ postInvalidateOnAnimation();
+ }
+ }
+
+ private int getOpenedOptionsY() {
+ return mStaticContent.getBottom();
+ }
+
+ private int getClosedOptionsY() {
+ return getOpenedOptionsY() + mClosedOptionsOffsetY;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ measureChild(mStaticContent, widthMeasureSpec, heightMeasureSpec);
+
+ if (mSummaryContent.getVisibility() != View.GONE) {
+ measureChild(mSummaryContent, widthMeasureSpec, heightMeasureSpec);
+ }
+
+ measureChild(mDynamicContent, widthMeasureSpec, heightMeasureSpec);
+
+ final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+// // The height of the draggable content may change and if that happens
+// // we have to adjust the current offset to ensure the sliding area is
+// // at the same position.
+// mCurrentOptionsOffsetY -= mDraggableContent.getMeasuredHeight()
+// - oldDraggableHeight;
+
+ if (mOldDraggableHeight != mDraggableContent.getMeasuredHeight()) {
+ mCurrentOptionsOffsetY -= mDraggableContent.getMeasuredHeight()
+ - mOldDraggableHeight;
+ mOldDraggableHeight = mDraggableContent.getMeasuredHeight();
+ }
+
+ // The height of the draggable content may change and if that happens
+ // we have to adjust the sliding area closed state offset.
+ mClosedOptionsOffsetY = mSummaryContent.getMeasuredHeight()
+ - mDraggableContent.getMeasuredHeight();
+
+ // The content host must be maximally large size that fits entirely
+ // on the screen when the options are collapsed.
+ ViewGroup.LayoutParams params = mEmbeddedContentContainer.getLayoutParams();
+ if (params.height == 0) {
+ params.height = heightSize - mStaticContent.getMeasuredHeight()
+ - mSummaryContent.getMeasuredHeight() - mDynamicContent.getMeasuredHeight()
+ + mDraggableContent.getMeasuredHeight();
+
+ mCurrentOptionsOffsetY = mClosedOptionsOffsetY;
+ }
+
+ // The content host can grow vertically as much as needed - we will be covering it.
+ final int hostHeightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+ measureChild(mEmbeddedContentContainer, widthMeasureSpec, hostHeightMeasureSpec);
+
+ setMeasuredDimension(resolveSize(MeasureSpec.getSize(widthMeasureSpec), widthMeasureSpec),
+ resolveSize(heightSize, heightMeasureSpec));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ mStaticContent.layout(left, top, right, mStaticContent.getMeasuredHeight());
+
+ if (mSummaryContent.getVisibility() != View.GONE) {
+ mSummaryContent.layout(left, mStaticContent.getMeasuredHeight(), right,
+ mStaticContent.getMeasuredHeight() + mSummaryContent.getMeasuredHeight());
+ }
+
+ final int dynContentTop = mStaticContent.getMeasuredHeight() + mCurrentOptionsOffsetY;
+ final int dynContentBottom = dynContentTop + mDynamicContent.getMeasuredHeight();
+
+ mDynamicContent.layout(left, dynContentTop, right, dynContentBottom);
+
+ final int embContentTop = mStaticContent.getMeasuredHeight() + mClosedOptionsOffsetY
+ + mDynamicContent.getMeasuredHeight();
+ final int embContentBottom = embContentTop + mEmbeddedContentContainer.getMeasuredHeight();
+
+ mEmbeddedContentContainer.layout(left, embContentTop, right, embContentBottom);
+ }
+
+ private void onDragProgress(float progress) {
+ final int summaryCount = mSummaryContent.getChildCount();
+ for (int i = 0; i < summaryCount; i++) {
+ View child = mSummaryContent.getChildAt(i);
+ child.setAlpha(progress);
+ }
+
+ if (progress == 0) {
+ if (mOptionsStateChangeListener != null) {
+ mOptionsStateChangeListener.onOptionsOpened();
+ }
+ mSummaryContent.setVisibility(View.GONE);
+ mExpandCollapseIcon.setBackgroundResource(R.drawable.ic_expand_less);
+ } else {
+ mSummaryContent.setVisibility(View.VISIBLE);
+ }
+
+ final float inverseAlpha = 1.0f - progress;
+
+ final int optionCount = mOptionsContainer.getChildCount();
+ for (int i = 0; i < optionCount; i++) {
+ View child = mOptionsContainer.getChildAt(i);
+ child.setAlpha(inverseAlpha);
+ }
+
+ if (mMoreOptionsContainer.getVisibility() != View.GONE) {
+ final int moreOptionCount = mMoreOptionsContainer.getChildCount();
+ for (int i = 0; i < moreOptionCount; i++) {
+ View child = mMoreOptionsContainer.getChildAt(i);
+ child.setAlpha(inverseAlpha);
+ }
+ }
+
+ if (inverseAlpha == 0) {
+ if (mOptionsStateChangeListener != null) {
+ mOptionsStateChangeListener.onOptionsClosed();
+ }
+ if (mMoreOptionsContainer.getVisibility() != View.GONE) {
+ mMoreOptionsContainer.setVisibility(View.INVISIBLE);
+ }
+ mDraggableContent.setVisibility(View.INVISIBLE);
+ mExpandCollapseIcon.setBackgroundResource(R.drawable.ic_expand_more);
+ } else {
+ if (mMoreOptionsContainer.getVisibility() != View.GONE) {
+ mMoreOptionsContainer.setVisibility(View.VISIBLE);
+ }
+ mDraggableContent.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private final class DragCallbacks extends ViewDragHelper.Callback {
+ @Override
+ public boolean tryCaptureView(View child, int pointerId) {
+ return child == mDynamicContent && pointerId == FIRST_POINTER_ID;
+ }
+
+ @Override
+ public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
+ mCurrentOptionsOffsetY += dy;
+ final float progress = ((float) top - getOpenedOptionsY())
+ / (getClosedOptionsY() - getOpenedOptionsY());
+
+ mDraggableContent.notifySubtreeAccessibilityStateChangedIfNeeded();
+
+ onDragProgress(progress);
+ }
+
+ public void onViewReleased(View child, float velocityX, float velocityY) {
+ final int childTop = child.getTop();
+
+ final int openedOptionsY = getOpenedOptionsY();
+ final int closedOptionsY = getClosedOptionsY();
+
+ if (childTop == openedOptionsY || childTop == closedOptionsY) {
+ return;
+ }
+
+ final int halfRange = closedOptionsY + (openedOptionsY - closedOptionsY) / 2;
+ if (childTop < halfRange) {
+ mDragger.smoothSlideViewTo(child, child.getLeft(), closedOptionsY);
+ } else {
+ mDragger.smoothSlideViewTo(child, child.getLeft(), openedOptionsY);
+ }
+
+ invalidate();
+ }
+
+ public int getViewVerticalDragRange(View child) {
+ return mDraggableContent.getHeight();
+ }
+
+ public int clampViewPositionVertical(View child, int top, int dy) {
+ final int staticOptionBottom = mStaticContent.getBottom();
+ return Math.max(Math.min(top, getOpenedOptionsY()), getClosedOptionsY());
+ }
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/FirstFocusableEditText.java b/packages/PrintSpooler/src/com/android/printspooler/widget/FirstFocusableEditText.java
new file mode 100644
index 0000000..d6bb7c8
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/FirstFocusableEditText.java
@@ -0,0 +1,69 @@
+/*
+ * 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.printspooler.widget;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.EditText;
+
+/**
+ * An instance of this class class is intended to be the first focusable
+ * in a layout to which the system automatically gives focus. It performs
+ * some voodoo to avoid the first tap on it to start an edit mode, rather
+ * to bring up the IME, i.e. to get the behavior as if the view was not
+ * focused.
+ */
+public final class FirstFocusableEditText extends EditText {
+ private boolean mClickedBeforeFocus;
+ private CharSequence mError;
+
+ public FirstFocusableEditText(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean performClick() {
+ super.performClick();
+ if (isFocused() && !mClickedBeforeFocus) {
+ clearFocus();
+ requestFocus();
+ }
+ mClickedBeforeFocus = true;
+ return true;
+ }
+
+ @Override
+ public CharSequence getError() {
+ return mError;
+ }
+
+ @Override
+ public void setError(CharSequence error, Drawable icon) {
+ setCompoundDrawables(null, null, icon, null);
+ mError = error;
+ }
+
+ protected void onFocusChanged(boolean gainFocus, int direction,
+ Rect previouslyFocusedRect) {
+ if (!gainFocus) {
+ mClickedBeforeFocus = false;
+ }
+ super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+ }
+}
\ No newline at end of file
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java
new file mode 100644
index 0000000..23c8d08
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java
@@ -0,0 +1,166 @@
+/*
+ * 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.printspooler.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.printspooler.R;
+
+/**
+ * This class is a layout manager for the print options. The options are
+ * arranged in a configurable number of columns and enough rows to fit all
+ * the options given the column count.
+ */
+@SuppressWarnings("unused")
+public final class PrintOptionsLayout extends ViewGroup {
+
+ private final int mColumnCount;
+
+ public PrintOptionsLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ TypedArray typedArray = context.obtainStyledAttributes(attrs,
+ R.styleable.PrintOptionsLayout);
+ mColumnCount = typedArray.getInteger(R.styleable.PrintOptionsLayout_columnCount, 0);
+ typedArray.recycle();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+
+ final int columnWidth = (widthSize != 0)
+ ? (widthSize - mPaddingLeft - mPaddingRight) / mColumnCount : 0;
+
+ int width = 0;
+ int height = 0;
+ int childState = 0;
+
+ final int childCount = getChildCount();
+ final int rowCount = childCount / mColumnCount + childCount % mColumnCount;
+
+ for (int row = 0; row < rowCount; row++) {
+ int rowWidth = 0;
+ int rowHeight = 0;
+
+ for (int col = 0; col < mColumnCount; col++) {
+ final int childIndex = row * mColumnCount + col;
+
+ if (childIndex >= childCount) {
+ break;
+ }
+
+ View child = getChildAt(childIndex);
+
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+
+ MarginLayoutParams childParams = (MarginLayoutParams) child.getLayoutParams();
+
+ final int childWidthMeasureSpec;
+ if (columnWidth > 0) {
+ childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+ columnWidth - childParams.getMarginStart() - childParams.getMarginEnd(),
+ MeasureSpec.EXACTLY);
+ } else {
+ childWidthMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
+ getPaddingStart() + getPaddingEnd() + width, childParams.width);
+ }
+
+ final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
+ getPaddingTop() + getPaddingBottom() + height, childParams.height);
+
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+
+ childState = combineMeasuredStates(childState, child.getMeasuredState());
+
+ rowWidth += child.getMeasuredWidth() + childParams.getMarginStart()
+ + childParams.getMarginEnd();
+
+ rowHeight = Math.max(rowHeight, child.getMeasuredHeight() + childParams.topMargin
+ + childParams.bottomMargin);
+ }
+
+ width = Math.max(width, rowWidth);
+ height += rowHeight;
+ }
+
+ width += getPaddingStart() + getPaddingEnd();
+ width = Math.max(width, getMinimumWidth());
+
+ height += getPaddingTop() + getPaddingBottom();
+ height = Math.max(height, getMinimumHeight());
+
+ setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, childState),
+ resolveSizeAndState(height, heightMeasureSpec,
+ childState << MEASURED_HEIGHT_STATE_SHIFT));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final int childCount = getChildCount();
+ final int rowCount = childCount / mColumnCount + childCount % mColumnCount;
+
+ int cellStart = getPaddingStart();
+ int cellTop = getPaddingTop();
+
+ for (int row = 0; row < rowCount; row++) {
+ int rowHeight = 0;
+
+ for (int col = 0; col < mColumnCount; col++) {
+ final int childIndex = row * mColumnCount + col;
+
+ if (childIndex >= childCount) {
+ break;
+ }
+
+ View child = getChildAt(childIndex);
+
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+
+ MarginLayoutParams childParams = (MarginLayoutParams) child.getLayoutParams();
+
+ final int childLeft = cellStart + childParams.getMarginStart();
+ final int childTop = cellTop + childParams.topMargin;
+ final int childRight = childLeft + child.getMeasuredWidth();
+ final int childBottom = childTop + child.getMeasuredHeight();
+
+ child.layout(childLeft, childTop, childRight, childBottom);
+
+ cellStart = childRight + childParams.getMarginEnd();
+
+ rowHeight = Math.max(rowHeight, child.getMeasuredHeight()
+ + childParams.topMargin + childParams.bottomMargin);
+ }
+
+ cellStart = getPaddingStart();
+ cellTop += cellTop + rowHeight;
+ }
+ }
+
+ @Override
+ public LayoutParams generateLayoutParams(AttributeSet attrs) {
+ return new ViewGroup.MarginLayoutParams(getContext(), attrs);
+ }
+}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 0e025a9..a92ab7e 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -195,4 +195,7 @@
<!-- Default for Settings.Secure.WAKE_GESTURE_ENABLED -->
<bool name="def_wake_gesture_enabled">true</bool>
+ <!-- Default for Settings.Global.GUEST_USER_ENABLED -->
+ <bool name="def_guest_user_enabled">true</bool>
+
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index c4a54b7..09e6a94 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -70,7 +70,7 @@
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 104;
+ private static final int DATABASE_VERSION = 105;
private Context mContext;
private int mUserHandle;
@@ -1677,6 +1677,24 @@
upgradeVersion = 104;
}
+ if (upgradeVersion < 105) {
+ if (mUserHandle == UserHandle.USER_OWNER) {
+ db.beginTransaction();
+ SQLiteStatement stmt = null;
+ try {
+ stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
+ + " VALUES(?,?);");
+ loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
+ R.bool.def_guest_user_enabled);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ if (stmt != null) stmt.close();
+ }
+ }
+ upgradeVersion = 105;
+ }
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
@@ -2410,6 +2428,8 @@
loadSetting(stmt, Settings.Global.DEVICE_NAME, getDefaultDeviceName());
+ loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
+ R.bool.def_guest_user_enabled);
// --- New global settings start here
} finally {
if (stmt != null) stmt.close();
@@ -2468,7 +2488,7 @@
}
private String getDefaultDeviceName() {
- return mContext.getResources().getString(R.string.def_device_name, Build.BRAND,
+ return mContext.getResources().getString(R.string.def_device_name, Build.MANUFACTURER,
Build.MODEL);
}
}
diff --git a/packages/Shell/res/values-ja/strings.xml b/packages/Shell/res/values-ja/strings.xml
index 88b9c14..db34041 100644
--- a/packages/Shell/res/values-ja/strings.xml
+++ b/packages/Shell/res/values-ja/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"シェル"</string>
<string name="bugreport_finished_title" msgid="2293711546892863898">"バグレポートが記録されました"</string>
- <string name="bugreport_finished_text" msgid="3559904746859400732">"タップしてバグレポートを共有する"</string>
+ <string name="bugreport_finished_text" msgid="3559904746859400732">"バグレポートを共有するにはタップします"</string>
<string name="bugreport_confirm" msgid="5130698467795669780">"バグレポートには、個人の非公開情報など、システムのさまざまなログファイルのデータが含まれます。共有する場合は信頼するアプリとユーザーのみを選択してください。"</string>
<string name="bugreport_confirm_repeat" msgid="4926842460688645058">"このメッセージを次回も表示する"</string>
</resources>
diff --git a/packages/SystemUI/res/anim/recents_from_app_enter.xml b/packages/SystemUI/res/anim/recents_from_app_enter.xml
new file mode 100644
index 0000000..6abe8b3
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_from_app_enter.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false"
+ android:zAdjustment="top">
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="0"/>
+</set>
diff --git a/packages/SystemUI/res/anim/recents_from_app_exit.xml b/packages/SystemUI/res/anim/recents_from_app_exit.xml
new file mode 100644
index 0000000..1447a5a
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_from_app_exit.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false"
+ android:zAdjustment="normal">
+
+ <!-- Animate the view out only after recents is visible -->
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="1"/>
+</set>
diff --git a/packages/SystemUI/res/anim/recents_from_launcher_enter.xml b/packages/SystemUI/res/anim/recents_from_launcher_enter.xml
index 4bd7e82..305a82f 100644
--- a/packages/SystemUI/res/anim/recents_from_launcher_enter.xml
+++ b/packages/SystemUI/res/anim/recents_from_launcher_enter.xml
@@ -19,10 +19,10 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false"
- android:zAdjustment="top">
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:zAdjustment="normal">
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/accelerate_cubic"
- android:duration="250"/>
+ android:interpolator="@android:interpolator/linear"
+ android:duration="200"/>
</set>
diff --git a/packages/SystemUI/res/anim/recents_from_launcher_exit.xml b/packages/SystemUI/res/anim/recents_from_launcher_exit.xml
index becc9d0..863591f 100644
--- a/packages/SystemUI/res/anim/recents_from_launcher_exit.xml
+++ b/packages/SystemUI/res/anim/recents_from_launcher_exit.xml
@@ -19,10 +19,10 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false"
- android:zAdjustment="normal">
+ android:zAdjustment="top">
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/decelerate_cubic"
- android:duration="250"/>
+ android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:duration="200"/>
</set>
diff --git a/packages/SystemUI/res/anim/recents_from_unknown_enter.xml b/packages/SystemUI/res/anim/recents_from_unknown_enter.xml
new file mode 100644
index 0000000..f68a143
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_from_unknown_enter.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false"
+ android:zAdjustment="top">
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="200"/>
+</set>
diff --git a/packages/SystemUI/res/anim/recents_from_unknown_exit.xml b/packages/SystemUI/res/anim/recents_from_unknown_exit.xml
new file mode 100644
index 0000000..31cf26a
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_from_unknown_exit.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false"
+ android:zAdjustment="normal">
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="200"/>
+</set>
diff --git a/packages/SystemUI/res/anim/recents_to_launcher_enter.xml b/packages/SystemUI/res/anim/recents_to_launcher_enter.xml
new file mode 100644
index 0000000..adcefe0
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_to_launcher_enter.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false"
+ android:zAdjustment="normal">
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/fast_out_linear_in"
+ android:duration="200"/>
+</set>
diff --git a/packages/SystemUI/res/anim/recents_to_launcher_exit.xml b/packages/SystemUI/res/anim/recents_to_launcher_exit.xml
new file mode 100644
index 0000000..863591f
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_to_launcher_exit.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false"
+ android:zAdjustment="top">
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:duration="200"/>
+</set>
diff --git a/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
deleted file mode 100644
index e6af81e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
index 873ca7e..b28624f 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
index 9d3cf53..9ce434d 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
index 288d36a..51dce69 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png
index 266d34d..3f3e288 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png
index 0298054..9856cbf 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png
index 91e2edf..6910456 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png
index 9ed15a7..e8c6ec6 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png
index 6f2915b..06dcd20 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png
index 3f3b692..240f536 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png
new file mode 100644
index 0000000..d4fdbf3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_nav_bar_background.9.png b/packages/SystemUI/res/drawable-hdpi/recents_nav_bar_background.9.png
deleted file mode 100644
index 6cd1176..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_nav_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
deleted file mode 100644
index 5ce8708..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_no_sim.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
index 3f7c4b0..e464347 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
index 956bb7c..f8b59e8 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent.png
deleted file mode 100644
index 86e2947..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index d8ab8ea..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
index a53aef1..1b578a6 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
index e1b2145..80ecaba 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent.png
deleted file mode 100644
index dffc059..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index c0209b0..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
index 2d8f81d..c7bf2c7 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
index 61c6d11..278de42 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent.png
deleted file mode 100644
index a67ed6d..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index 6101333..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
index 90eece6..464831c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
index 382cf23..c24132c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent.png
deleted file mode 100644
index ca1c8c4..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index cfef88d..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
index a4b3b37..bc84f22 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
index ee5f623..f4e219e 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent.png
deleted file mode 100644
index ca3c541..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index 78d4490..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
index 3d21350..ece2e37 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
index 40fbaec..d524dcf 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent.png
deleted file mode 100644
index 77bef31..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index d79f5b7..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
index 61b4569..373e84a 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
index 1a0312b..e5a102a 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent.png
deleted file mode 100644
index d04916e..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index d940d34..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
index 8715a11..6b19593 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
index 487a0b1..a5e0686 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent.png
deleted file mode 100644
index a7cff47..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index 0a60bb6..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-mdpi/battery_low_battery.png
deleted file mode 100644
index e865f4c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/battery_low_battery.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
index 225d924..f878093 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
index 7779d57..7780b16 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
index 37d17d2..343d0dd 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png
index 5e70a07..8e9583b 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png
index 39a0c07..7d38703 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png
index 5bbf3fe..6e186a3 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png
index 798f62f..12b4042 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png
index f8e549a..e2a89c3 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png
index c7fda96..311720b 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png
new file mode 100644
index 0000000..9fc1a3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_nav_bar_background.9.png b/packages/SystemUI/res/drawable-mdpi/recents_nav_bar_background.9.png
deleted file mode 100644
index 7237f09..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_nav_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
deleted file mode 100644
index bdf0f67..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_no_sim.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
index 3361e34..67e4ee7 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png
index ed52bc3..dfef430 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
index b380327..de6d109 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png
index 49df31b..7d0c3fbe 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png
index ac45bcd..3baeb52 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png
index 9fb4266..d5b48e8 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png
index 459d011..26d7e7b 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png
index e1cddde..c49198d 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png
index e459f2c..2a21f29 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
index 0ec4d23..538d7d1 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png
index 4dedcbe..eb8e80b 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
index e55f2bf..1c2c35a 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png
index a39c3e5..eec613f 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png
index 80e988f..1c0bad8 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png
index 4ef12b0d..1293fa8 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png
index 8ef12a8..96a9cce 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png
index c2977c0..9ffc80a 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png
index 60ec10e..aa9b57b 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
index 8aa6e3a..b343522 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png
index e272b62..f2f7b50 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
index bf68b22..383398c 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png
index 59ef663..53444ab 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png
index cf3a5ff..4294937 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png
index 2598954..7cb3ee4 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png
index 66853db..b017946 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png
index c46fd026..e8dd07c 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png
index 0e84d92..f396ea9 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
index 7e96395e..1b817cf 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png
index cb94580..21b7a06 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
index 382ef39..676fc14 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png
index 8d7be53..26f4ba9 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png
index 613fba0..ea21b60 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png
index 0511ad1..c7d77c2 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png
index 77fe9b2..ae12cfd 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png
index ae78eb0..8c27d45 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png
index 5b446b1..c98827c 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-xhdpi/battery_low_battery.png
deleted file mode 100644
index 83693c1..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/battery_low_battery.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
index a2bb50a..ec2951d 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
index 24897ce..5103190 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
index aaeeb1b..818aa4f 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png
index ddee461..254f757 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png
index 23a7997..f0de417 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png
index 9f200c2..97f1526 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png
index 43e9bc2..773fa94 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png
index 5c0ba82..8a8e941 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png
index b76a0ca..ad7dfc3 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png
new file mode 100644
index 0000000..f38de93
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_nav_bar_background.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_nav_bar_background.9.png
deleted file mode 100644
index 8d56a1d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/recents_nav_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_no_sim.png
deleted file mode 100644
index 461535c..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_no_sim.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-xxhdpi/battery_low_battery.png
deleted file mode 100644
index cebbb15..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/battery_low_battery.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
index 79cfcee..77969b8 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png
index 7959f65..b171f92 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
index c3bfcfb..ad35c65 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png
index 64f6a22..d60229f 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png
index 8fd36bc..8fffa8e 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png
index 6f30e54..9215055 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png
index 024ef8f..bcf7eb1 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png
index 6e0b071..a261f85 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png
index 9a56987..4c612f7 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png
new file mode 100644
index 0000000..8194605
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/recents_lower_gradient.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_nav_bar_background.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_nav_bar_background.9.png
deleted file mode 100644
index aed300b..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/recents_nav_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_no_sim.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_no_sim.png
deleted file mode 100644
index 7b03a11..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_no_sim.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_05.xml b/packages/SystemUI/res/drawable/ic_notify_zen.xml
similarity index 61%
copy from packages/SystemUI/res/drawable/ic_qs_location_05.xml
copy to packages/SystemUI/res/drawable/ic_notify_zen.xml
index 1a21e2f..c46455b 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_05.xml
+++ b/packages/SystemUI/res/drawable/ic_notify_zen.xml
@@ -15,14 +15,14 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:width="24dp"
+ android:height="24dp"/>
<viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
<path
android:fill="#FFFFFFFF"
- android:pathData="M12.0,13.0c-1.74,0.0 -3.15,1.41 -3.15,3.15C8.85,18.51 12.0,22.0 12.0,22.0s3.15,-3.49 3.15,-5.85C15.15,14.41 13.74,13.0 12.0,13.0zM12.0,17.27c-0.62,0.0 -1.13,-0.5 -1.13,-1.12c0.0,-0.62 0.5,-1.12 1.13,-1.12c0.62,0.0 1.12,0.5 1.12,1.12C13.12,16.77 12.62,17.27 12.0,17.27z"/>
+ android:pathData="M4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0s20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0S4.0,13.0 4.0,24.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8zM8.0,24.0c0.0,-3.7 1.3,-7.1 3.4,-9.8L33.8,36.6C31.1,38.7 27.7,40.0 24.0,40.0C15.2,40.0 8.0,32.8 8.0,24.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_01.xml b/packages/SystemUI/res/drawable/ic_power_low.xml
similarity index 66%
rename from packages/SystemUI/res/drawable/ic_qs_location_01.xml
rename to packages/SystemUI/res/drawable/ic_power_low.xml
index ff37d9a..5bb7aba 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_01.xml
+++ b/packages/SystemUI/res/drawable/ic_power_low.xml
@@ -15,14 +15,14 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:width="24.0dp"
+ android:height="24.0dp"/>
<viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
<path
android:fill="#FFFFFFFF"
- android:pathData="M12.0,2.0C8.13,2.0 5.0,5.13 5.0,9.0c0.0,5.25 7.0,13.0 7.0,13.0s7.0,-7.75 7.0,-13.0C19.0,5.13 15.87,2.0 12.0,2.0zM12.0,11.5c-1.38,0.0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5c1.38,0.0 2.5,1.12 2.5,2.5S13.38,11.5 12.0,11.5z"/>
+ android:pathData="M30.0,6.0L30.0,2.0L18.0,2.0l0.0,4.0l-8.0,0.0l0.0,40.0l28.0,0.0L38.0,6.0L30.0,6.0zM26.0,37.0l-4.0,0.0l0.0,-4.0l4.0,0.0L26.0,37.0zM26.0,30.0l-4.0,0.0L22.0,15.0l4.0,0.0L26.0,30.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_01.xml b/packages/SystemUI/res/drawable/ic_power_saver.xml
similarity index 66%
copy from packages/SystemUI/res/drawable/ic_qs_location_01.xml
copy to packages/SystemUI/res/drawable/ic_power_saver.xml
index ff37d9a..26e7375 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_01.xml
+++ b/packages/SystemUI/res/drawable/ic_power_saver.xml
@@ -15,14 +15,14 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:width="24.0dp"
+ android:height="24.0dp"/>
<viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
<path
android:fill="#FFFFFFFF"
- android:pathData="M12.0,2.0C8.13,2.0 5.0,5.13 5.0,9.0c0.0,5.25 7.0,13.0 7.0,13.0s7.0,-7.75 7.0,-13.0C19.0,5.13 15.87,2.0 12.0,2.0zM12.0,11.5c-1.38,0.0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5c1.38,0.0 2.5,1.12 2.5,2.5S13.38,11.5 12.0,11.5z"/>
+ android:pathData="M30.0,6.0L30.0,2.0L18.0,2.0l0.0,4.0l-8.0,0.0l0.0,40.0l28.0,0.0L38.0,6.0L30.0,6.0zM32.0,28.0l-6.0,0.0l0.0,6.0l-4.0,0.0l0.0,-6.0l-6.0,0.0l0.0,-4.0l6.0,0.0l0.0,-6.0l4.0,0.0l0.0,6.0l6.0,0.0L32.0,28.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_color_inversion.xml b/packages/SystemUI/res/drawable/ic_qs_color_inversion.xml
deleted file mode 100644
index dc30a53..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_color_inversion.xml
+++ /dev/null
@@ -1,28 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:fill="#FFFFFFFF"
- android:pathData="M18.939,7.244c-5.887,-5.885 -6.214,-6.214 -6.222,-6.222l-0.707,-0.737L5.088,7.207c-2.914,2.915 -3.74,6.629 -2.266,10.19c1.541,3.719 5.312,6.316 9.174,6.317l0.0,0.0c3.861,-0.001 7.636,-2.603 9.179,-6.328C22.646,13.834 21.832,10.138 18.939,7.244zM4.67,16.632c-1.149,-2.776 -0.481,-5.696 1.832,-8.011l5.494,-5.492c0.0,0.002 0.002,0.003 0.003,0.004l0.0,18.582c-0.001,0.0 -0.002,0.0 -0.003,0.0C8.922,21.714 5.91,19.624 4.67,16.632z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml
new file mode 100644
index 0000000..b6a5cad
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
+
+ <path
+ android:fill="#4DFFFFFF"
+ android:pathData="M41.3,41.7L36.6,37.0L24.0,24.5l-7.1,-7.1L14.0,14.5L8.5,9.0L6.0,11.5l5.6,5.6c-5.1,6.3 -4.7,15.5 1.1,21.4c3.1,3.1 7.2,4.7 11.3,4.7c3.6,0.0 7.1,-1.2 10.1,-3.6l5.4,5.4l2.5,-2.5L41.3,41.7zM24.0,39.2c-3.2,0.0 -6.2,-1.2 -8.5,-3.5c-2.3,-2.3 -3.5,-5.3 -3.5,-8.5c0.0,-2.6 0.9,-5.1 2.4,-7.2l9.6,9.6L24.0,39.2zM24.0,10.2l0.0,9.2l14.5,14.5c2.7,-5.9 1.7,-13.1 -3.2,-18.0L24.0,4.5l0.0,0.0l0.0,0.0L16.6,12.0l2.8,2.8L24.0,10.2z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_05.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
similarity index 68%
rename from packages/SystemUI/res/drawable/ic_qs_location_05.xml
rename to packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
index 1a21e2f..e8d59e0 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_05.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
@@ -19,10 +19,10 @@
android:height="64dp"/>
<viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
<path
android:fill="#FFFFFFFF"
- android:pathData="M12.0,13.0c-1.74,0.0 -3.15,1.41 -3.15,3.15C8.85,18.51 12.0,22.0 12.0,22.0s3.15,-3.49 3.15,-5.85C15.15,14.41 13.74,13.0 12.0,13.0zM12.0,17.27c-0.62,0.0 -1.13,-0.5 -1.13,-1.12c0.0,-0.62 0.5,-1.12 1.13,-1.12c0.62,0.0 1.12,0.5 1.12,1.12C13.12,16.77 12.62,17.27 12.0,17.27z"/>
+ android:pathData="M35.3,15.9L24.0,4.5l0.0,0.0l0.0,0.0L12.7,15.9c-6.2,6.2 -6.2,16.4 0.0,22.6c3.1,3.1 7.2,4.7 11.3,4.7s8.2,-1.6 11.3,-4.7C41.6,32.2 41.6,22.1 35.3,15.9zM24.0,39.2L24.0,39.2c-3.2,0.0 -6.2,-1.2 -8.5,-3.5c-2.3,-2.3 -3.5,-5.3 -3.5,-8.5s1.2,-6.2 3.5,-8.5l8.5,-8.5L24.0,39.2z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_02.xml b/packages/SystemUI/res/drawable/ic_qs_location_02.xml
deleted file mode 100644
index bb4465f..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_02.xml
+++ /dev/null
@@ -1,28 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:fill="#FFFFFFFF"
- android:pathData="M12.0,4.0c-3.48,0.0 -6.3,2.82 -6.3,6.3C5.7,15.02 12.0,22.0 12.0,22.0s6.3,-6.98 6.3,-11.7C18.3,6.82 15.48,4.0 12.0,4.0zM12.0,12.55c-1.24,0.0 -2.25,-1.01 -2.25,-2.25S10.76,8.05 12.0,8.05c1.24,0.0 2.25,1.01 2.25,2.25S13.24,12.55 12.0,12.55z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_03.xml b/packages/SystemUI/res/drawable/ic_qs_location_03.xml
deleted file mode 100644
index 956a8c3..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_03.xml
+++ /dev/null
@@ -1,28 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:fill="#FFFFFFFF"
- android:pathData="M12.0,7.0c-2.9,0.0 -5.25,2.35 -5.25,5.25C6.75,16.19 12.0,22.0 12.0,22.0s5.25,-5.81 5.25,-9.75C17.25,9.35 14.9,7.0 12.0,7.0zM12.0,14.12c-1.04,0.0 -1.88,-0.84 -1.88,-1.88s0.84,-1.88 1.88,-1.88c1.04,0.0 1.87,0.84 1.87,1.88S13.04,14.12 12.0,14.12z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_04.xml b/packages/SystemUI/res/drawable/ic_qs_location_04.xml
deleted file mode 100644
index 0c0fb3b..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_04.xml
+++ /dev/null
@@ -1,28 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:fill="#FFFFFFFF"
- android:pathData="M12.0,10.0c-2.32,0.0 -4.2,1.88 -4.2,4.2C7.8,17.35 12.0,22.0 12.0,22.0s4.2,-4.65 4.2,-7.8C16.2,11.88 14.32,10.0 12.0,10.0zM12.0,15.7c-0.83,0.0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5c0.83,0.0 1.5,0.67 1.5,1.5S12.83,15.7 12.0,15.7z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_06.xml b/packages/SystemUI/res/drawable/ic_qs_location_06.xml
deleted file mode 100644
index 5642a8a2..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_06.xml
+++ /dev/null
@@ -1,31 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:fill="#FFFFFFFF"
- android:pathData="M12.0,16.0c-1.16,0.0 -2.1,0.94 -2.1,2.1C9.9,19.67 12.0,22.0 12.0,22.0s2.1,-2.33 2.1,-3.9C14.1,16.94 13.16,16.0 12.0,16.0zM12.0,18.85c-0.41,0.0 -0.75,-0.34 -0.75,-0.75s0.34,-0.75 0.75,-0.75c0.41,0.0 0.75,0.34 0.75,0.75S12.41,18.85 12.0,18.85z"/>
- <path
- android:pathData="M11.99,15c-1.35,0,-2.45,1.1,-2.45,2.45 c0,1.84,2.45,4.55,2.45,4.55s2.45,-2.71,2.45,-4.55C14.44,16.1,13.34,15,11.99,15z M11.99,18.33c-0.48,0,-0.88,-0.39,-0.88,-0.88 s0.39,-0.88,0.88,-0.88c0.48,0,0.87,0.39,0.87,0.88S12.47,18.33,11.99,18.33z"
- android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_07.xml b/packages/SystemUI/res/drawable/ic_qs_location_07.xml
deleted file mode 100644
index 1ad2ebc..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_07.xml
+++ /dev/null
@@ -1,28 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:pathData="M12,9c-2.51,0,-4.55,2.04,-4.55,4.55 C7.45,16.96,12,22,12,22s4.55,-5.04,4.55,-8.45C16.55,11.04,14.51,9,12,9z M12,15.18c-0.9,0,-1.63,-0.73,-1.63,-1.62 s0.73,-1.62,1.63,-1.62c0.9,0,1.62,0.73,1.62,1.62S12.9,15.18,12,15.18z"
- android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_09.xml b/packages/SystemUI/res/drawable/ic_qs_location_09.xml
deleted file mode 100644
index 6169af5..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_09.xml
+++ /dev/null
@@ -1,28 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:pathData="M12,4c-3.48,0,-6.3,2.82,-6.3,6.3 C5.7,15.02,12,22,12,22s6.3,-6.98,6.3,-11.7C18.3,6.82,15.48,4,12,4z M12,12.55c-1.24,0,-2.25,-1.01,-2.25,-2.25S10.76,8.05,12,8.05 c1.24,0,2.25,1.01,2.25,2.25S13.24,12.55,12,12.55z"
- android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_10.xml b/packages/SystemUI/res/drawable/ic_qs_location_10.xml
deleted file mode 100644
index 93e2eb4..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_10.xml
+++ /dev/null
@@ -1,28 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:pathData="M12,3C8.33,3,5.35,5.98,5.35,9.65 C5.35,14.64,12,22,12,22s6.65,-7.36,6.65,-12.35C18.65,5.98,15.67,3,12,3z M12,12.02c-1.31,0,-2.38,-1.06,-2.38,-2.38 S10.69,7.28,12,7.28c1.31,0,2.37,1.06,2.37,2.37S13.31,12.02,12,12.02z"
- android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_11.xml b/packages/SystemUI/res/drawable/ic_qs_location_11.xml
deleted file mode 100644
index 09a3e63..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location_11.xml
+++ /dev/null
@@ -1,28 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" >
- <size
- android:width="64dp"
- android:height="64dp"/>
-
- <viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
-
- <path
- android:pathData="M12,2C8.13,2,5,5.13,5,9c0,5.25,7,13,7,13s7,-7.75,7,-13 C19,5.13,15.87,2,12,2z M12,11.5c-1.38,0,-2.5,-1.12,-2.5,-2.5s1.12,-2.5,2.5,-2.5c1.38,0,2.5,1.12,2.5,2.5S13.38,11.5,12,11.5z"
- android:fill="#4DFFFFFF"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_off.xml b/packages/SystemUI/res/drawable/ic_qs_location_off.xml
index d28d347..26ebfbf 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_off.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 The Android Open Source Project
@@ -14,18 +13,19 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<animation-list
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:oneshot="true">
- <item android:drawable="@drawable/ic_qs_location_01" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_02" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_03" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_04" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_05" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_06" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_07" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_08" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_09" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_10" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_11" android:duration="16" />
-</animation-list>
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
+
+ <path
+ android:fill="#4DFFFFFF"
+ android:pathData="M24.0,13.0c2.8,0.0 5.0,2.2 5.0,5.0c0.0,1.5 -0.7,2.8 -1.7,3.7l7.3,7.3c2.0,-3.7 3.4,-7.6 3.4,-11.0c0.0,-7.7 -6.3,-14.0 -14.0,-14.0c-4.0,0.0 -7.5,1.6 -10.1,4.3l6.4,6.4C21.2,13.6 22.5,13.0 24.0,13.0zM32.7,32.2l-9.3,-9.3l-0.2,-0.2L6.5,6.0L4.0,8.5l6.4,6.4c-0.2,1.0 -0.4,2.0 -0.4,3.1c0.0,10.5 14.0,26.0 14.0,26.0s3.3,-3.7 6.8,-8.7l6.7,6.7l2.5,-2.5L32.7,32.2z"/>
+ <path
+ android:pathData="M23.5,22.9l0.0,0.0 -0.20000076,-0.19999886z"
+ android:fill="#4DFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_on.xml b/packages/SystemUI/res/drawable/ic_qs_location_on.xml
index 72512ac..bc73005 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_on.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 The Android Open Source Project
@@ -14,18 +13,16 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<animation-list
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:oneshot="true">
- <item android:drawable="@drawable/ic_qs_location_11" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_10" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_09" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_08" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_07" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_06" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_05" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_04" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_03" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_02" android:duration="16" />
- <item android:drawable="@drawable/ic_qs_location_01" android:duration="16" />
-</animation-list>
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="64dp"
+ android:height="64dp"/>
+
+ <viewport
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M24.0,4.0c-7.7,0.0 -14.0,6.3 -14.0,14.0c0.0,10.5 14.0,26.0 14.0,26.0s14.0,-15.5 14.0,-26.0C38.0,10.3 31.7,4.0 24.0,4.0zM24.0,23.0c-2.8,0.0 -5.0,-2.2 -5.0,-5.0s2.2,-5.0 5.0,-5.0c2.8,0.0 5.0,2.2 5.0,5.0S26.8,23.0 24.0,23.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/notification_row_legacy_bg.xml b/packages/SystemUI/res/drawable/notification_row_legacy_bg.xml
deleted file mode 100644
index ce3372e..0000000
--- a/packages/SystemUI/res/drawable/notification_row_legacy_bg.xml
+++ /dev/null
@@ -1,22 +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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:exitFadeDuration="@android:integer/config_mediumAnimTime">
-
- <item android:state_pressed="true" android:drawable="@drawable/notification_item_background_color_pressed" />
- <item android:state_pressed="false" android:drawable="@drawable/notification_item_background_legacy_color" />
-</selector>
diff --git a/packages/SystemUI/res/drawable/qs_panel_background.xml b/packages/SystemUI/res/drawable/qs_panel_background.xml
index a1a5362..74876f7 100644
--- a/packages/SystemUI/res/drawable/qs_panel_background.xml
+++ b/packages/SystemUI/res/drawable/qs_panel_background.xml
@@ -16,5 +16,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/system_primary_color" />
<corners
- android:radius="@*android:dimen/notification_quantum_rounded_rect_radius"/>
+ android:radius="@*android:dimen/notification_material_rounded_rect_radius"/>
</shape>
diff --git a/packages/SystemUI/res/drawable/ripple_drawable.xml b/packages/SystemUI/res/drawable/ripple_drawable.xml
index d2bff42..af7941f 100644
--- a/packages/SystemUI/res/drawable/ripple_drawable.xml
+++ b/packages/SystemUI/res/drawable/ripple_drawable.xml
@@ -16,6 +16,4 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:tint="?android:attr/colorControlHighlight"
- android:tintMode="src_over"
- android:pinned="true" />
+ android:color="?android:attr/colorControlHighlight" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_08.xml b/packages/SystemUI/res/drawable/stat_sys_no_sim.xml
similarity index 71%
rename from packages/SystemUI/res/drawable/ic_qs_location_08.xml
rename to packages/SystemUI/res/drawable/stat_sys_no_sim.xml
index 179bc66..70948b7 100644
--- a/packages/SystemUI/res/drawable/ic_qs_location_08.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_no_sim.xml
@@ -15,14 +15,14 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:width="18dp"
+ android:height="18dp"/>
<viewport
android:viewportWidth="24.0"
android:viewportHeight="24.0"/>
<path
- android:pathData="M12,6c-3.09,0,-5.6,2.51,-5.6,5.6 C6.4,15.8,12,22,12,22s5.6,-6.2,5.6,-10.4C17.6,8.51,15.09,6,12,6z M12,13.6c-1.1,0,-2,-0.9,-2,-2s0.9,-2,2,-2c1.1,0,2,0.9,2,2 S13.1,13.6,12,13.6z"
- android:fill="#4DFFFFFF"/>
+ android:fill="#4DFFFFFF"
+ android:pathData="M19.0,5.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0l-7.0,0.0L7.7,5.3L19.0,16.7L19.0,5.0zM3.7,3.9L2.4,5.2L5.0,7.8L5.0,19.0c0.0,1.1 0.9,2.0 2.0,2.0l10.0,0.0c0.4,0.0 0.7,-0.1 1.0,-0.3l1.9,1.9l1.3,-1.3L3.7,3.9z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/status_bar_item_background.xml b/packages/SystemUI/res/drawable/status_bar_item_background.xml
deleted file mode 100644
index 3a50aa9..0000000
--- a/packages/SystemUI/res/drawable/status_bar_item_background.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2006 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<layer-list
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:opacity="translucent"
- >
- <item
- android:drawable="@drawable/notification_item_background_color"
- />
-</layer-list>
-
diff --git a/packages/SystemUI/res/drawable/ticker_background.xml b/packages/SystemUI/res/drawable/ticker_background.xml
deleted file mode 100644
index 7320fa0..0000000
--- a/packages/SystemUI/res/drawable/ticker_background.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2006 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<layer-list
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:opacity="translucent"
- >
- <!-- the large icon extends 12dp beyond the edge of the status bar -->
- <item
- android:drawable="@drawable/notification_item_background_color"
- android:top="12dp"
- />
-</layer-list>
-
diff --git a/packages/SystemUI/res/layout/battery_low.xml b/packages/SystemUI/res/layout/battery_low.xml
deleted file mode 100644
index 2373355..0000000
--- a/packages/SystemUI/res/layout/battery_low.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/layout/keyguard.xml
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/padding"
- android:orientation="vertical"
- android:gravity="center"
- android:padding="16dp"
- >
-
- <TextView android:id="@+id/subtitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="18sp"
- android:textColor="#ffffffff"
- android:gravity="start"
- android:text="@string/battery_low_subtitle"
- />
-
- <TextView android:id="@+id/level_percent"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="18sp"
- android:textColor="#ffffffff"
- android:gravity="start"
- android:paddingBottom="16dp"
- />
-
- <ImageView android:id="@+id/image"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/battery_low_battery"
- />
-
-</LinearLayout>
-
-
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 9bf42b2..db5983b 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -46,7 +46,7 @@
android:id="@+id/keyguard_indication_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="100dp"
+ android:layout_marginBottom="70dp"
android:layout_gravity="bottom|center_horizontal"
android:textStyle="italic"
android:textColor="#ffffff"
diff --git a/packages/SystemUI/res/layout/recents_empty.xml b/packages/SystemUI/res/layout/recents_empty.xml
index ac6450b..c0ddde1 100644
--- a/packages/SystemUI/res/layout/recents_empty.xml
+++ b/packages/SystemUI/res/layout/recents_empty.xml
@@ -21,7 +21,6 @@
android:gravity="center"
android:textSize="20sp"
android:textColor="#ffffffff"
- android:textStyle="italic"
android:text="@string/recents_empty_message"
android:fontFamily="sans-serif-light"
android:visibility="gone" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_nav_bar_scrim.xml b/packages/SystemUI/res/layout/recents_nav_bar_scrim.xml
index 463fee8..4245d49 100644
--- a/packages/SystemUI/res/layout/recents_nav_bar_scrim.xml
+++ b/packages/SystemUI/res/layout/recents_nav_bar_scrim.xml
@@ -20,4 +20,4 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:scaleType="fitXY"
- android:src="@drawable/recents_nav_bar_background" />
\ No newline at end of file
+ android:src="@drawable/recents_lower_gradient" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 85d2f16..23f2796 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -56,6 +56,7 @@
android:layout_marginEnd="4dp"
android:layout_gravity="center_vertical|end"
android:padding="18dp"
+ android:visibility="invisible"
android:src="@drawable/recents_dismiss_light" />
</com.android.systemui.recents.views.TaskBarView>
</com.android.systemui.recents.views.TaskView>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index eaa2558..aa62daa 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -111,47 +111,13 @@
/>
</LinearLayout>
</LinearLayout>
-
- <LinearLayout android:id="@+id/ticker"
+
+ <ViewStub
+ android:id="@+id/ticker_stub"
+ android:inflatedId="@+id/ticker"
+ android:layout="@layout/status_bar_ticker"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingStart="6dip"
- android:animationCache="false"
- android:orientation="horizontal" >
- <ImageSwitcher android:id="@+id/tickerIcon"
- android:layout_width="@dimen/status_bar_icon_size"
- android:layout_height="@dimen/status_bar_icon_size"
- android:layout_marginEnd="4dip"
- >
- <com.android.systemui.statusbar.AnimatedImageView
- android:layout_width="@dimen/status_bar_icon_size"
- android:layout_height="@dimen/status_bar_icon_size"
- android:scaleType="center"
- />
- <com.android.systemui.statusbar.AnimatedImageView
- android:layout_width="@dimen/status_bar_icon_size"
- android:layout_height="@dimen/status_bar_icon_size"
- android:scaleType="center"
- />
- </ImageSwitcher>
- <com.android.systemui.statusbar.phone.TickerView android:id="@+id/tickerText"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:paddingTop="2dip"
- android:paddingEnd="10dip">
- <TextView
- android:textAppearance="@style/TextAppearance.StatusBar.PhoneTicker"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- />
- <TextView
- android:textAppearance="@style/TextAppearance.StatusBar.PhoneTicker"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- />
- </com.android.systemui.statusbar.phone.TickerView>
- </LinearLayout>
+ />
+
</com.android.systemui.statusbar.phone.PhoneStatusBarView>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 7f34041..353368b 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -35,12 +35,66 @@
android:background="@drawable/notification_header_bg"
android:clickable="true"
/>
+
+ <View android:id="@+id/header_spacer"
+ android:layout_height="8dp"
+ android:layout_width="0dp" />
+
+ <TextView
+ android:id="@+id/header_emergency_calls_only"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_below="@id/header_spacer"
+ android:paddingTop="12dp"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ android:visibility="gone"
+ android:textAppearance="@style/TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"
+ android:text="@*android:string/emergency_calls_only" />
+
+ <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"
+ android:layout_width="40dp"
+ android:layout_height="@dimen/status_bar_header_height"
+ android:layout_alignParentEnd="true"
+ android:background="@null"
+ android:scaleType="centerInside"
+ android:padding="8dp" />
+
+ <ImageButton android:id="@+id/settings_button"
+ style="@android:style/Widget.Material.Button.Borderless"
+ android:layout_toStartOf="@id/multi_user_switch"
+ android:layout_width="48dp"
+ android:layout_height="@dimen/status_bar_header_height"
+ android:layout_marginStart="8dp"
+ android:src="@drawable/ic_settings_24dp"
+ android:contentDescription="@string/accessibility_desc_quick_settings"/>
+
+ <FrameLayout android:id="@+id/system_icons_container"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/status_bar_header_height"
+ android:layout_toStartOf="@id/multi_user_switch"
+ android:layout_marginEnd="2dp"
+ android:layout_marginStart="16dp"
+ />
+
+ <TextView
+ android:id="@+id/header_charging_info"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toEndOf="@id/system_icons_container"
+ android:layout_below="@id/header_spacer"
+ android:paddingTop="12dp"
+ android:paddingEnd="16dp"
+ android:paddingStart="4dp"
+ style="@style/TextAppearance.StatusBar.Expanded.ChargingInfo"/>
+
<RelativeLayout
android:id="@+id/datetime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
- android:paddingTop="16dp"
+ android:layout_below="@id/header_emergency_calls_only"
+ android:paddingTop="8dp"
android:paddingBottom="16dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
@@ -64,36 +118,11 @@
android:layout_below="@id/clock"
/>
</RelativeLayout>
-
- <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"
- android:layout_width="40dp"
- android:layout_height="@dimen/status_bar_header_height"
- android:layout_alignParentEnd="true"
- android:background="@null"
- android:scaleType="centerInside"
- android:padding="8dp"
- />
-
- <ImageButton android:id="@+id/settings_button"
- style="@android:style/Widget.Quantum.Button.Borderless"
- android:layout_toStartOf="@id/multi_user_switch"
- android:layout_width="56dp"
- android:layout_height="@dimen/status_bar_header_height"
- android:src="@drawable/ic_settings_24dp"
- android:contentDescription="@string/accessibility_desc_quick_settings"/>
-
- <FrameLayout android:id="@+id/system_icons_container"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/status_bar_header_height"
- android:layout_toStartOf="@id/multi_user_switch"
- android:layout_marginEnd="4dp"
- />
-
<com.android.keyguard.CarrierText
android:id="@+id/keyguard_carrier_text"
android:layout_width="match_parent"
android:layout_height="@dimen/status_bar_header_height_keyguard"
- android:layout_marginLeft="8dp"
+ android:layout_marginLeft="16dp"
android:layout_toStartOf="@id/system_icons_container"
android:gravity="center_vertical"
android:ellipsize="marquee"
@@ -105,6 +134,8 @@
layout="@layout/quick_settings_brightness_dialog"
android:id="@+id/brightness_container"
android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
/>
<TextView
diff --git a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
index 84d64b9..e220a16 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
@@ -18,48 +18,13 @@
<com.android.systemui.statusbar.SpeedBumpView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:focusable="true"
- android:clickable="true"
+ android:layout_height="@dimen/speed_bump_height"
android:visibility="gone"
>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="@dimen/speed_bump_height_collapsed"
- android:layout_gravity="top"
- android:orientation="horizontal">
- <com.android.systemui.statusbar.AlphaOptimizedView
- android:id="@+id/speedbump_line_left"
- android:layout_width="0dp"
- android:layout_height="1dp"
- android:layout_weight="1"
- android:background="#6fdddddd"
- android:layout_gravity="center_vertical"/>
- <com.android.systemui.statusbar.SpeedBumpDotsLayout
- android:id="@+id/speed_bump_dots_layout"
- android:layout_width="34dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:layout_height="match_parent"
- android:layout_weight="0"/>
- <com.android.systemui.statusbar.AlphaOptimizedView
- android:id="@+id/speedbump_line_right"
- android:layout_width="0dp"
- android:layout_height="1dp"
- android:layout_weight="1"
- android:background="#6fdddddd"
- android:layout_gravity="center_vertical"/>
- </LinearLayout>
- <TextView
- android:id="@+id/speed_bump_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"
- android:fontFamily="sans-serif-condensed"
- android:textSize="15sp"
- android:singleLine="true"
- android:textColor="#eeeeee"
- android:visibility="invisible"
- android:text="@string/speed_bump_explanation"
- android:paddingTop="4dp" />
+ <com.android.systemui.statusbar.AlphaOptimizedView
+ android:id="@+id/speedbump_line"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="#6fdddddd"
+ android:layout_gravity="center_vertical"/>
</com.android.systemui.statusbar.SpeedBumpView>
diff --git a/packages/SystemUI/res/layout/status_bar_ticker.xml b/packages/SystemUI/res/layout/status_bar_ticker.xml
new file mode 100644
index 0000000..dd9b3ef
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_ticker.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ - Copyright 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 android:id="@+id/ticker"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingStart="6dip"
+ android:animationCache="false"
+ android:orientation="horizontal">
+
+ <ImageSwitcher android:id="@+id/tickerIcon"
+ android:layout_width="@dimen/status_bar_icon_size"
+ android:layout_height="@dimen/status_bar_icon_size"
+ android:layout_marginEnd="4dip"
+ >
+ <com.android.systemui.statusbar.AnimatedImageView
+ android:layout_width="@dimen/status_bar_icon_size"
+ android:layout_height="@dimen/status_bar_icon_size"
+ android:scaleType="center"
+ />
+ <com.android.systemui.statusbar.AnimatedImageView
+ android:layout_width="@dimen/status_bar_icon_size"
+ android:layout_height="@dimen/status_bar_icon_size"
+ android:scaleType="center"
+ />
+ </ImageSwitcher>
+ <com.android.systemui.statusbar.phone.TickerView android:id="@+id/tickerText"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:paddingTop="2dip"
+ android:paddingEnd="10dip">
+ <TextView
+ android:textAppearance="@style/TextAppearance.StatusBar.PhoneTicker"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ />
+ <TextView
+ android:textAppearance="@style/TextAppearance.StatusBar.PhoneTicker"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ />
+ </com.android.systemui.statusbar.phone.TickerView>
+</LinearLayout>
+
diff --git a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
index 7671c354a..1928506 100644
--- a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
+++ b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
@@ -28,7 +28,7 @@
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:button="@null"
- android:background="@*android:drawable/switch_track_quantum"
+ android:background="@*android:drawable/switch_track_material"
android:visibility="gone"
/>
<com.android.systemui.settings.ToggleSeekBar
diff --git a/packages/SystemUI/res/layout/user_switcher_item.xml b/packages/SystemUI/res/layout/user_switcher_item.xml
index 43a85e7..8df2f5a 100644
--- a/packages/SystemUI/res/layout/user_switcher_item.xml
+++ b/packages/SystemUI/res/layout/user_switcher_item.xml
@@ -21,10 +21,12 @@
android:layout_width="match_parent"
android:layout_height="64dp"
android:orientation="horizontal"
+ android:gravity="center_vertical"
tools:context=".settings.UserSwitcherDialog">
<ImageView
- android:layout_width="64dp"
- android:layout_height="match_parent"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="4dp"
android:id="@+id/user_picture"
tools:src="@drawable/dessert_zombiegingerbread"/>
<TextView
@@ -37,4 +39,11 @@
android:gravity="center_vertical"
tools:text="Hiroshi Lockheimer"
/>
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginEnd="4dp"
+ android:src="@*android:drawable/ic_menu_delete"
+ android:id="@+id/user_delete"
+ android:background="?android:attr/selectableItemBackground"/>
</LinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index c642626..d9c4c0c 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Geen kennisgewings"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Voortdurend"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Kennisgewings"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Koppel herlaaier"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Die battery raak pap."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Battery is amper pap"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> oor"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> oor. Batteryspaarder is aan."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-laaiery nie ondersteun nie.\nGebruik net die laaier wat verskaf is."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Batterygebruik"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Laai met USB word nie gesteun nie."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Gebruik slegs die laaier wat verskaf is."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Instellings"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Aktiveer batteryspaarder?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Begin"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Aktiveer batteryspaarder"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Om die batteryleeftyd te help verbeter, sal Batteryspaarder jou toestel se werkverrigting verminder.\n\nBatteryspaarder sal gedeaktiveer word wanneer jou toestel ingeprop word."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Instellings"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Vliegtuigmodus"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Aan."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Af"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Gekoppel."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Koppel tans."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> toestelle)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth af"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Helderheid"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Outoroteer"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotasie gesluit"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Gesluit op portret"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Gesluit op landskap"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Outo-draai"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotasie is gesluit"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Portret"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Landskap"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Invoermetode"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Ligging"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Ligging af"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nie gekoppel nie"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Saai na skerm uit"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Uitsaaiskerm"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OUTO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Keer kleure om"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Geen onlangse programme nie"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Programinligting"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"soek"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Gelaai"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laai tans"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tot vol"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Laai nie"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk word\ndalk gemonitor"</string>
<string name="description_target_search" msgid="3091587249776033139">"Soek"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Gly op vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Raak om te wys"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Moenie steur nie"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d meer"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Minder dringende kennisgewings hieronder"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Tik weer om oop te maak"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Sleep op om te ontsluit"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Sleep regs vir foon"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Sleep links vir kamera"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Totdat jy dit afskakel"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laai tans (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Gas"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ gas"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Een minuut lank"</item>
<item quantity="other" msgid="6924190729213550991">"%d minute lank"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Een uur lank"</item>
<item quantity="other" msgid="5408537517529822157">"%d uur lank"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Batteryspaarder is aan"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Toestel se werkverrigting is verminder."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Maak batteryspaarder se instellings oop"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index d864f9f..f84f028 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"ምንም ማሳወቂያዎች የሉም"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"በመካሄድ ላይ ያለ"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"ማሳወቂያዎች"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"የኃይል መሙያ አገናኝ።"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"ባትሪው እያነሰ ነው።"</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"የባትሪ ኃይል አነስተኛ ነው"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> ቀሪ"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> ይቀራል። የባትሪ ኃይል ቆጣቢ በርቷል።"</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB ኃይል መሙያ አይታገዝም።\n የቀረበውን ኃይል መሙያ ብቻ ተጠቀም።"</string>
- <string name="battery_low_why" msgid="7279169609518386372">"የባትሪ ጥቅም"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"የUSB ኃይል መሙላት አይደገፍም።"</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"የቀረበውን ኃይል መሙያ ብቻ ይጠቀሙ።"</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"ቅንብሮች"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"የባህሪ ኃይል ቆጣቢው ይጀመር?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"ጀምር"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"የባህሪ ኃይል ቆጣቢው ይጀመር"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"የባትሪ በህይወት የመቆየት ጊዜን ለማሻሻል እንዲያግዝ፣ የባትሪ ኃይል ቆጣቢው የመሳሪያዎን የመስራት አቅም ይቀንሰዋል።\n\nየባትሪ ኃይል ቆጣቢው መሳሪያዎ የተሰካ ሲሆን ይሰናከላል።"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ቅንብሮች"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"የአውሮፕላን ሁነታ"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"በርቷል።"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"ጠፍቷል።"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"ተገናኝቷል።"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"በማገናኘት ላይ።"</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ብሉቱዝ (<xliff:g id="NUMBER">%d</xliff:g> መሣሪያዎች)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ብሉቱዝ ጠፍቷል"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"ብሩህነት"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"ራስ-አዙር"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"አዙሪት ተቆልፏል"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"ወደ ቁመት አቀማመጥ ተቆልፏል"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"ወደ መሬት ገጽታ ተቆልፏል"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"በራስ ሰር አሽከርክር"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"አዙሪት ተቆልፏል"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"ምስል ገላጭ"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"በወርድ"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"የግቤት ስልት"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"አካባቢ"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"አካባቢ ጠፍቷል"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"አልተገናኘም"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"ማያ ገጽ ውሰድ"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"ማያ ገጽ ውሰድ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ብሩህነት"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ራስ-ሰር"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"ቀለማትን ግልብጥ"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"ምንም የቅርብ ጊዜ መተግበሪያዎች የሉም"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"የመተግበሪያ መረጃ"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ፈልግ"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ባትሪ ሞልቷል"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"ኃይል በመሙላት ላይ"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> እስኪሞላ ድረስ"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"ባትሪ እየሞላ አይደለም"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"አውታረ መረብ\nክትትል ሊደረግበት ይችላል"</string>
<string name="description_target_search" msgid="3091587249776033139">"ፍለጋ"</string>
<string name="description_direction_up" msgid="7169032478259485180">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ላይ አንሸራትት።"</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"ለማሳየት ነካ ያድርጉ"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"አይረብሹ"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d ተጨማሪ"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"በጣም አስቸካይ ያልሆኑ ማሳወቂያዎች ከታች"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"ለመክፈት ዳግም መታ ያድርጉ"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"ለማስከፈት ወደ ላይ ያንሸራትቱ"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"ለስልክ ወደቀኝ ያንሸራትቱ"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"ለካሜራ ወደግራ ያንሸራትቱ"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"ይህን እስኪያጠፉት ድረስ"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ሃይል በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"እንግዳ"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ እንግዳ"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"ለአንድ ደቂቃ"</item>
<item quantity="other" msgid="6924190729213550991">"ለ%d ደቂቃዎች"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"ለአንድ ሰዓት"</item>
<item quantity="other" msgid="5408537517529822157">"ለ%d ሰዓቶች"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"የባትሪ ኃይል ቆጣቢ በርቷል"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"የመሳሪያው የአሰራር ብቃት ተቀንሷል።"</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"የባትሪ ኃይል ቆጣቢ ቅንብሮች"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 3906bfa..44e6ffe 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"ليس هناك أي اشعارات"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"مستمر"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"الإشعارات"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"توصيل الشاحن"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"انخفضت طاقة البطارية."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"البطارية منخفضة"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"المتبقي: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"يتبقى <xliff:g id="NUMBER">%d%%</xliff:g>. وضع توفير الطاقة قيد التشغيل."</string>
<string name="invalid_charger" msgid="4549105996740522523">"شحن USB غير معتمد.\nاستخدم الشاحن الموفر فقط."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"استخدام البطارية"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"لا يمكن إجراء الشحن عبر USB."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"لا تستخدم سوى الشاحن المزوّد."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"الإعدادات"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"هل تريد بدء وضع توفير الطاقة؟"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"بدء"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"بدء وضع توفير الطاقة"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"للمساعدة في إطالة عمر البطارية، فإن وضع توفير الطاقة سيقلل من أداء جهازك.\n\nسيتم تعطيل وضع توفير الطاقة عند توصيل جهازك بالشاحن."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"الإعدادات"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"وضع الطائرة"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"تم التشغيل."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"تم الإيقاف."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"متصل."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"جارٍ الاتصال."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"بلوتوث (<xliff:g id="NUMBER">%d</xliff:g> من الأجهزة)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"إيقاف البلوتوث"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"السطوع"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"تدوير تلقائي"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"تم قفل التدوير"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"تم القفل على الوضع العمودي"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"تم القفل على الوضع الأفقي"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"دوران تلقائي"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"تم قفل التدوير"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"عمودي"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"أفقي"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"أسلوب الإدخال"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"الموقع"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"الموقع قيد الإيقاف"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"ليست متصلة"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"بث الشاشة"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"شاشة Cast"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"السطوع"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"تلقائي"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"قلب الألوان"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"ليست هناك تطبيقات حديثة"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"معلومات التطبيق"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"بحث"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"تم الشحن"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"جارٍ الشحن"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> حتى الاكتمال"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"لا يتم الشحن"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"قد تكون الشبكة\nخاضعة للرقابة"</string>
<string name="description_target_search" msgid="3091587249776033139">"بحث"</string>
<string name="description_direction_up" msgid="7169032478259485180">"تمرير لأعلى لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"المس للعرض"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"الرجاء عدم الإزعاج"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d أخرى"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"الإشعارات الأقل إلحاحًا أدناه"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"انقر مرة أخرى للفتح"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"مرر سريعًا لأعلى لإلغاء القفل"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"مرر سريعًا إلى اليسار لفتح الهاتف"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"مرر سريعًا إلى اليمين لفتح الكاميرا"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"لحين تعطيل هذا الإعداد"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"جارٍ الشحن (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الامتلاء)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"المدعو"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ مدعو"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"لمدة دقيقة واحدة"</item>
<item quantity="other" msgid="6924190729213550991">"لمدة %d من الدقائق"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"لمدة ساعة واحدة"</item>
<item quantity="other" msgid="5408537517529822157">"لمدة %d من الساعات"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"وضع توفير الطاقة قيد التشغيل"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"تم تقليل أداء الجهاز."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"فتح إعدادات وضع توفير الطاقة"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 6ef23ad..71fb8b8 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Няма известия"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"В момента"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Известия"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Включете зарядното устройство"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Батерията се изтощава."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Батерията е изтощена"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Остава: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Остава: <xliff:g id="NUMBER">%d%%</xliff:g>. Режимът за запазване на батерията е включен."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Не се поддържа зареждане през USB.\nИзползвайте само доставеното зарядно устройство."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Използване на батерията"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Зареждането през USB не се поддържа."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Използвайте само предоставеното зарядно устройство."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Настройки"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Да се стартира ли режимът за запазване на батерията?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Стартиране"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Стартиране на режима за запазване на батерията"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"С цел удължаване на живота на батерията режимът за запазването й ще намали ефективността на устройството ви.\n\nКогато то е включено в захранването, режимът ще се деактивира."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Самолетен режим"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Вкл."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Изкл."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Има връзка."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Установява се връзка."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> устройства)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth е изключен"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Яркост"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Автоматична ориентация"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Ориентацията е заключена"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Заключено във вертикален режим"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Заключено в хоризонтален режим"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Автоматична ориентация"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Ориентацията е заключена"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Вертикален режим"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Хоризонтален режим"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Метод на въвеждане"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Местоположение"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Местоположението е изключено"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Няма връзка"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Екран за предаване"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Екран за предаване"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркост"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТ."</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Обръщане на цветовете"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Няма скорошни приложения"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Информация за приложението"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"търсене"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заредена"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Зарежда се"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> до пълно зареждане"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Не се зарежда"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежата може\nда се наблюдава"</string>
<string name="description_target_search" msgid="3091587249776033139">"Търсене"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Плъзнете нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Докоснете за показване"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Не ме безпокойте"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Още %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Ппоказване на по-малко спешните известия по-долу"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Докоснете отново, за да отворите"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Прекарайте пръст нагоре, за да отключите"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Прекарайте пръст надясно, за да използвате телефона"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Прекарайте пръст наляво, за да включите камерата"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Докато не изключите това"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарежда се (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Гост"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ гост"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"За една минута"</item>
<item quantity="other" msgid="6924190729213550991">"За %d минути"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"За един час"</item>
<item quantity="other" msgid="5408537517529822157">"За %d часа"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Режимът за запазване на батерията е включен"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Ефективността на устройството е намалена."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Отваряне на настройките за режима за запазване на батерията"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 9e3495e..becd731 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Cap notificació"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Continu"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificacions"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Connecta el carregador"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"La bateria comença a estar baixa."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Queda poca bateria"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restant"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Queda un <xliff:g id="NUMBER">%d%%</xliff:g>. La funció Estalvi de bateria està activada."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Càrrega d\'USB no admesa.\nUtilitza només el carregador proporcionat."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Ús de la bateria"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"La càrrega per USB no és compatible."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Fes servir només el carregador proporcionat amb el dispositiu."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Configuració"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Vols iniciar la funció Estalvi de bateria?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Inicia"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Inicia la funció Estalvi de bateria"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"La funció Estalvi de bateria reduirà el rendiment del dispositiu per tal d\'augmentar la durada de la bateria.\n\nAquesta funció es desactivarà quan el dispositiu estigui connectat."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configuració"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode d\'avió"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Activat."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Desactivat."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Connectat."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"S’està connectant."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositius)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desactivat"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Brillantor"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Rotació automàtica"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotació bloquejada"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Bloquejat en mode vertical"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Bloquejat en mode horitzontal"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Rotació automàtica"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotació bloquejada"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Vertical"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Horitzontal"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Mètode d\'entrada"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Ubicació"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Ubicació desactivada"</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Desconnectat"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Pantalla d\'emissió"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Pantalla d\'emissió"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillantor"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÀTICA"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverteix els colors"</string>
@@ -218,6 +223,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"No hi ha aplicacions recents."</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informació de l\'aplicació"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"S\'està carregant"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> per completar la càrrega"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"No s\'està carregant"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"És possible que la xarxa\nestigui controlada"</string>
<string name="description_target_search" msgid="3091587249776033139">"Cerca"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Fes lliscar el dit cap amunt per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -228,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toca per mostrar-ho."</string>
<string name="zen_mode_title" msgid="8793432092004749188">"No molesteu"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d més"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Notificacions menys urgents a continuació"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Torna a tocar per obrir-la."</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Fes lliscar el dit cap amunt per desbloquejar el teclat."</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Fes lliscar el dit cap a la dreta per obrir el telèfon."</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Fes lliscar el dit cap a l\'esquerra per obrir la càmera."</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Fins que no ho desactivis"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la càrrega)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Convidat"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Convidat"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Durant un minut"</item>
<item quantity="other" msgid="6924190729213550991">"Durant %d minuts"</item>
@@ -243,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Durant una hora"</item>
<item quantity="other" msgid="5408537517529822157">"Durant %d hores"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"La funció Estalvi de bateria està activada."</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"S\'ha reduït el rendiment del dispositiu."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Obre la configuració de la funció Estalvi de bateria"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 6050da4..97efe46 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Žádná oznámení"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Probíhající"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Oznámení"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Připojte nabíječku"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Baterie je vybitá."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Baterie je slabá"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Zbývá <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Zbývá <xliff:g id="NUMBER">%d%%</xliff:g>. Režim Úspora baterie je zapnutý."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Nabíjení pomocí rozhraní USB není podporováno.\nPoužívejte pouze nabíječku, která byla dodána se zařízením."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Využití baterie"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Nabíjení přes USB není podporováno."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Používejte pouze nabíječku, která je součástí balení."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Nastavení"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Aktivovat režim Úspora baterie?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Spustit"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Aktivovat režim Úspora baterie"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"V režimu Úspora baterie se omezí výkon zařízení, aby se tak prodloužila výdrž baterie.\n\nRežim Úspora baterie se deaktivuje, když bude zařízení zapojeno do zásuvky."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavení"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Režim V letadle"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Zapnuto."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Vypnuto."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Připojeno."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Připojování."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> zařízení)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Rozhraní Bluetooth je vypnuto"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Jas"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automatické otáčení"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Otáčení je uzamčeno"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Uzamčen režim na výšku"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Uzamčen režim na šířku"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatické otáčení"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Otáčení je uzamčeno"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Na výšku"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Na šířku"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Metoda zadávání dat"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Poloha"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Poloha vypnuta"</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nepřipojeno"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Vzdálená obrazovka"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Odesílání obrazovky"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jas"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Převrátit barvy"</string>
@@ -218,6 +223,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Žádné nedávné aplikace"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informace o aplikaci"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"vyhledat"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nabito"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nabíjení"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do plného nabití"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nenabíjí se"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Síť může být\nmonitorována"</string>
<string name="description_target_search" msgid="3091587249776033139">"Vyhledávání"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Přejeďte prstem nahoru: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
@@ -228,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Oznámení zobrazíte kliknutím"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Nerušit"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Další: %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Méně urgentní oznámení níže"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Oznámení otevřete opětovným klepnutím"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Zařízení odemknete přejetím prstem nahoru"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Telefon otevřete přejetím prstem vpravo."</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Fotoaparát otevřete přejetím prstem vlevo."</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Dokud tuto funkci nevypnete"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Host"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Přidat hosta"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Na jednu minutu"</item>
<item quantity="other" msgid="6924190729213550991">"Na %d min"</item>
@@ -243,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Na jednu hodinu"</item>
<item quantity="other" msgid="5408537517529822157">"Na %d h"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Režim Úspora baterie je zapnutý."</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Výkon zařízení je snížen."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otevřít nastavení režimu Úspora baterie"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 830bebf..a86157d 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen underretninger"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"I gang"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Underretninger"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Tilslut oplader"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteriet er ved at være fladt."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Batteriniveauet er lavt"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> tilbage"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> tilbage. Batteribesparende er slået til."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Opladning via USB understøttes ikke.\nBrug kun den medfølgende oplader."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Batteriforbrug"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB-opladning understøttes ikke."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Brug kun den oplader, der føler med."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Indstillinger"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Vil du starte Batteribesparende?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Startet"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Start Batteribesparende"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"For at hjælpe med at forbedre batteriets levetid, reducerer Batteribesparende enhedens ydeevne.\n\nBatteribesparende slukkes, når strømstikket er sat i."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Indstillinger"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flytilstand"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Til."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Fra."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Forbundet."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Opretter forbindelse..."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheder)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth slået fra"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Lysstyrke"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automatisk rotation"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotation er låst"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Altid stående"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Altid liggende"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Roter automatisk"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotationen er låst"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Stående"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Liggende"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Inputmetode"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Placering"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Placering fra"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ikke forbundet"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Cast skærm"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Skærm til casting"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Byt om på farver"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Der er ingen seneste apps"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Oplysninger om applikationen"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opladet"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Oplader"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> indtil fuld opladet"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Oplader ikke"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netværket kan\nvære overvåget"</string>
<string name="description_target_search" msgid="3091587249776033139">"Søgning"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Glid op for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Tryk for at vise"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Vil ikke forstyrres"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d mere"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre presserende underretninger nedenfor"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Tryk igen for at åbne"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Stryg for at låse op"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Stryg til højre for at bruge telefonen"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Stryg til venstre for at åbne kameraet"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Indtil du slår denne indstilling fra"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Gæst"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Gæst"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"I ét minut"</item>
<item quantity="other" msgid="6924190729213550991">"I %d minutter"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"I én time"</item>
<item quantity="other" msgid="5408537517529822157">"I %d timer"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Batteribesparende er slået til"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Enhedens ydeevne reduceres."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Åbn indstillinger for Batteribesparende"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 72c9d64..40e623a 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Keine Benachrichtigungen"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktuell"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Benachrichtigungen"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Ladegerät anschließen"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Akku ist fast leer."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Akku ist schwach"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Noch <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Noch <xliff:g id="NUMBER">%d%%</xliff:g>. Energiesparmodus ist aktiviert."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-Aufladung wird nicht unterstützt.\nVerwenden Sie das mitgelieferte Aufladegerät."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Akkuverbrauch"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Laden per USB wird nicht unterstützt."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Verwenden Sie nur das im Lieferumfang enthaltene Ladegerät."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Einstellungen"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Energiesparmodus starten?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Starten"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Energiesparmodus starten"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Im Energiesparmodus wird zur Schonung des Akkus die Leistung des Geräts herabgesetzt.\n\nSobald Ihr Gerät an eine Stromquelle angeschlossen ist, wird der Energiesparmodus deaktiviert."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Einstellungen"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WLAN"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flugmodus"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"An"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Aus"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Verbunden"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Verbindung wird hergestellt."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Geräte)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth aus"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Helligkeit"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Autom. drehen"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Drehung gesperrt"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Auf Hochformat gesperrt"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Auf Querformat gesperrt"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatisch drehen"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Drehung gesperrt"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Hochformat"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Querformat"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Eingabemethode"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Standort"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Standort aus"</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nicht verbunden"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Bildschirm übertragen"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Bildschirmübertragung"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helligkeit"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Farben umkehren"</string>
@@ -218,6 +223,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Keine neuen Apps"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"App-Info"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Aufgeladen"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Wird aufgeladen"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Voll in <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Wird nicht aufgeladen"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netzwerk wird\neventuell überwacht."</string>
<string name="description_target_search" msgid="3091587249776033139">"Suche"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach oben schieben"</string>
@@ -228,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Zum Ansehen tippen"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Nicht stören"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d mehr"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Weniger dringende Benachrichtigungen unten"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Erneut tippen, um Benachrichtigung zu öffnen"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Zum Entsperren nach oben wischen"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Zum Öffnen des Telefons nach rechts wischen"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Zum Öffnen der Kamera nach links wischen"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Bis zur Deaktivierung"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Wird aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Gast"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Gast"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Für eine Minute"</item>
<item quantity="other" msgid="6924190729213550991">"Für %d Minuten"</item>
@@ -243,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Für eine Stunde"</item>
<item quantity="other" msgid="5408537517529822157">"Für %d Stunden"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Energiesparmodus ist aktiviert"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Die Geräteleistung wurde herabgesetzt."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Einstellungen für den Energiesparmodus öffnen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 2d3f246..5e5aa6a 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Δεν υπάρχουν ειδοποιήσεις"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Εν εξελίξει"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ειδοποιήσεις"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Συνδέστε φορτιστή"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Η στάθμη της μπαταρίας είναι χαμηλή."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Χαμηλή στάθμη μπαταρίας"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Απομένει <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Απομένει <xliff:g id="NUMBER">%d%%</xliff:g>. Η Εξοικονόμηση μπαταρίας είναι ενεργή."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Δεν υποστηρίζεται η φόρτιση USB.\nΧρησιμοποιείτε μόνο τον φορτιστή που παρέχεται."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Χρήση μπαταρίας"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Δεν υποστηρίζεται η φόρτιση μέσω USB."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Χρήση μόνο του παρεχόμενου φορτιστή."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Ρυθμίσεις"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Έναρξη Εξοικονόμησης μπαταρίας;"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Έναρξη"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Έναρξη Εξοικονόμησης μπαταρίας"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Για να συμβάλει στη βελτίωση της διάρκειας ζωής της μπαταρίας, η Εξοικονόμηση μπαταρίας θα μειώσει την απόδοση της συσκευής σας.\n\nΗ Εξοικονόμηση μπαταρίας θα απενεργοποιηθεί όταν η συσκευή σας συνδεθεί για φόρτιση."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ρυθμίσεις"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Λειτουργία πτήσης"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Ενεργό."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Ανενεργό."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Έχει συνδεθεί."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Σύνδεση."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> συσκευές)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Απενεργοποιημένο Bluetooth"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Φωτεινότητα"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Αυτόματη περιστροφή"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Η περιστροφή είναι κλειδωμένη"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Κλειδωμένο στην κατακόρυφη προβολή"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Κλειδωμένο στην οριζόντια προβολή"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Αυτόματη περιστροφή"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Η περιστροφή είναι κλειδωμένη"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Κατακόρυφα"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Οριζόντια"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Μέθοδος εισαγωγής"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Τοποθεσία"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Τοποθεσία απενεργοποιημένη"</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Μη συνδεδεμένο"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Μετάδοση οθόνης"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Μετάδοση οθόνης"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Φωτεινότητα"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ΑΥΤΟΜΑΤΗ"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Αντιστροφή χρωμάτων"</string>
@@ -218,6 +223,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Καμία πρόσφατη εφαρμογή"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Φορτίστηκε"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Φόρτιση"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> για πλήρη φόρτιση"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Δεν φορτίζει"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Το δίκτυο μπορεί\nνα παρακολουθείται"</string>
<string name="description_target_search" msgid="3091587249776033139">"Αναζήτηση"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Κύλιση προς τα επάνω για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -228,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Αγγίξτε για εμφάνιση"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Μην ενοχλείτε"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d ακόμη"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Λιγότερο επείγουσες ειδοποιήσεις παρακάτω"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Πατήστε ξανά για να ανοίξετε"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Σύρετε για να ξεκλειδώσετε"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Σύρετε προς τα δεξιά για το τηλέφωνο"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Σύρετε αριστερά για τη φωτογραφική μηχανή"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Μέχρι να το απενεργοποιήσετε"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Επισκέπτης"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Επισκέπτης"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Για ένα λεπτό"</item>
<item quantity="other" msgid="6924190729213550991">"Για %d λεπτά"</item>
@@ -243,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Για μία ώρα"</item>
<item quantity="other" msgid="5408537517529822157">"Για %d ώρες"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Η Εξοικονόμηση μπαταρίας είναι ενεργή"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Η απόδοση της συσκευής μειώνεται."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Άνοιγμα ρυθμίσεων Εξοικονόμησης μπαταρίας"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 66233cc..82ee78c 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No notifications"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ongoing"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Connect charger"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"The battery is getting low."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Battery is low"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> remaining"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> remaining. Battery saver is on."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB charging not supported.\nUse only the supplied charger."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Battery use"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB charging not supported."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Use only the supplied charger."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Settings"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Start battery saver?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Start"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Start battery saver"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"To help improve battery life, Battery saver will reduce your device’s performance.\n\nBattery saver will be disabled when your device is plugged in."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Aeroplane mode"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"On."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Off."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Connected."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Connecting."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Devices)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Off"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Brightness"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Auto Rotate"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotation Locked"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Locked to Portrait"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Locked to Landscape"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Auto-rotate"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotation locked"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Portrait"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Landscape"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Input Method"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Location"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Location Off"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Not Connected"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Cast Screen"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Cast screen"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invert colours"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"No recent apps"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Charged"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Charging"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> until full"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Not charging"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
<string name="description_target_search" msgid="3091587249776033139">"Search"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Touch to show"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Do not disturb"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d more"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Less urgent notifications below"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Swipe right for phone"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Swipe left for camera"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Until you turn this off"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Guest"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Guest"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"For one minute"</item>
<item quantity="other" msgid="6924190729213550991">"For %d minutes"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"For one hour"</item>
<item quantity="other" msgid="5408537517529822157">"For %d hours"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Device performance is reduced."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Open battery saver settings"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 66233cc..82ee78c 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No notifications"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ongoing"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Connect charger"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"The battery is getting low."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Battery is low"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> remaining"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> remaining. Battery saver is on."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB charging not supported.\nUse only the supplied charger."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Battery use"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB charging not supported."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Use only the supplied charger."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Settings"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Start battery saver?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Start"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Start battery saver"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"To help improve battery life, Battery saver will reduce your device’s performance.\n\nBattery saver will be disabled when your device is plugged in."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Aeroplane mode"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"On."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Off."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Connected."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Connecting."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Devices)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Off"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Brightness"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Auto Rotate"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotation Locked"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Locked to Portrait"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Locked to Landscape"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Auto-rotate"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotation locked"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Portrait"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Landscape"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Input Method"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Location"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Location Off"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Not Connected"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Cast Screen"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Cast screen"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invert colours"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"No recent apps"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Charged"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Charging"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> until full"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Not charging"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
<string name="description_target_search" msgid="3091587249776033139">"Search"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Touch to show"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Do not disturb"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d more"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Less urgent notifications below"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Swipe right for phone"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Swipe left for camera"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Until you turn this off"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Guest"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Guest"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"For one minute"</item>
<item quantity="other" msgid="6924190729213550991">"For %d minutes"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"For one hour"</item>
<item quantity="other" msgid="5408537517529822157">"For %d hours"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Device performance is reduced."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Open battery saver settings"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 0810ee7..4145a29 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No hay notificaciones"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Continuo"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Conecta el cargador."</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Hay poca batería."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Batería baja"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Quedan <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> restante. El ahorro de batería está activado."</string>
<string name="invalid_charger" msgid="4549105996740522523">"No admite la carga USB.\nUsa sólo el cargador provisto."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Uso de la batería"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"No se admite la carga por USB."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Usa solo el cargador suministrado."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Configuración"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"¿Quieres iniciar el ahorro de batería?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Iniciar"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Iniciar ahorro de batería"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Para ayudar a mejorar la duración de la batería, el ahorro de batería reducirá el rendimiento del dispositivo.\n\nEsta función se inhabilitará cuando el dispositivo esté conectado."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configuración"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo avión"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Activado"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Desactivado"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Conectado"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Conectando"</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desactivado"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Brillo"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Girar automáticamente"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotación bloqueada"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Bloqueada en vertical"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Bloqueada en horizontal"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Rotación automática"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotación bloqueada"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Vertical"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Horizontal"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Método de introducción"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Ubicación"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Ubicación desactivada"</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Sin conexión"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Pantalla de Cast"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Transmitir pantalla"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invertir colores"</string>
@@ -215,10 +220,13 @@
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Anclaje a red"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Zona"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notificaciones"</string>
- <!-- no translation found for recents_empty_message (7883614615463619450) -->
- <skip />
+ <string name="recents_empty_message" msgid="7883614615463619450">"No hay aplicaciones recientes."</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Cargando"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> para completarse"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"No se está cargando"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Es posible que la red\nesté supervisada."</string>
<string name="description_target_search" msgid="3091587249776033139">"Buscar"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -229,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toca para mostrar"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"No molestar"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d más"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Notificaciones menos urgentes abajo"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Presionar de nuevo para abrir"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Deslizar el dedo hacia arriba para desbloquear"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Desliza hacia la derecha para abrir el teléfono."</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Desliza hacia la izquierda para acceder a la cámara."</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Hasta que lo desactives"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (faltan <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Invitado"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Agregar invitado"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item>
<item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
@@ -244,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Durante una hora"</item>
<item quantity="other" msgid="5408537517529822157">"Durante %d horas"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Rendimiento del dispositivo reducido"</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir configuración del ahorro de batería"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index ad92c24..b1dc302 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No tienes notificaciones"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Entrante"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Conecta el cargador"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Se está agotando la batería."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Nivel de batería bajo"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> restante. Ahorro de batería activado."</string>
<string name="invalid_charger" msgid="4549105996740522523">"No se admite la carga por USB.\nUtiliza solo el cargador proporcionado."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Uso de la batería"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"No se admite la carga por USB."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Utiliza solo el cargador proporcionado."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Ajustes"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"¿Iniciar ahorro de batería?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Iniciar"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Iniciar ahorro de batería"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Para ayudar a mejorar la duración de la batería, la función de ahorro de energía reducirá el rendimiento del dispositivo.\n\nEsta función estará inhabilitada cuando el dispositivo esté enchufado."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ajustes"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo avión"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Sí"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"No"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Conectado"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Conectando."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desactivado"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Brillo"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Girar automáticamente"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotación bloqueada"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Bloqueado en vertical"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Bloqueado en horizontal"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Girar automáticamente"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotación bloqueada"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Vertical"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Horizontal"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Método de entrada"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Ubicación"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Ubicación desactivada"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"No conectado"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Enviar contenido a pantalla"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Pantalla de Cast"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invertir colores"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"No hay aplicaciones recientes"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Cargando"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> para completarse"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"No se está cargando"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La red se\npuede supervisar"</string>
<string name="description_target_search" msgid="3091587249776033139">"Buscar"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toca para mostrar"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"No molestar"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d más"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Notificaciones menos urgente abajo"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Toca de nuevo para abrir"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Desliza el dedo hacia arriba para desbloquear"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Desliza el dedo hacia la izquierda para acceder al teléfono"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Desliza el dedo hacia la izquierda para acceder a la cámara"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Hasta apagar el dispositivo"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Invitado"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Añadir invitado"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Durante un minuto"</item>
<item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Durante una hora"</item>
<item quantity="other" msgid="5408537517529822157">"Durante %d horas"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Rendimiento del dispositivo reducido."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir ajustes de la función de ahorro de batería"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 71e2af6..8aab7f3 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Teatisi pole"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Jätkuv"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Teadistused"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Ühendage laadija"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Aku hakkab tühjenema."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Aku hakkab tühjaks saama"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> on alles"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Alles: <xliff:g id="NUMBER">%d%%</xliff:g>. Akusäästja on sisse lülitatud."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB laadimist ei toetata.\nKasutage ainult tootja laadija."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Akukasutus"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB-ga laadimist ei toetata."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Kasutage ainult kaasasolevat laadijat."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Seaded"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Kas käivitada akusäästja?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Käivita"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Käivita akusäästja"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Aku tööea parandamiseks vähendab akusäästja teie seadme jõudlust.\n\nKui seade ühendatakse toiteallikaga, keelatakse akusäästja."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Seaded"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WiFi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lennurežiim"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Sees."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Väljas."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Ühendatud."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Ühenduse loomine."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> seadet)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth on väljas"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Heledus"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automaatne pööramine"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Pööramine lukus"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Lukustatud vertikaalpaigutusse"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Lukustatud horisontaalpaigutusse"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automaatne pööramine"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Pööramine on lukustatud"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Vertikaalpaigutus"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Horisontaalpaigutus"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Sisestusmeetod"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Asukoht"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Asukoht on väljas"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ühendus puudub"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Cast-ekraan"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Ülekandeekraan"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Heledus"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAATNE"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Vaheta värve"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Hiljutisi rakendusi pole"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Rakenduste teave"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"otsing"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laetud"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laadimine"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Täislaadimiseks kulub <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ei laadi"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Võrku võidakse\njälgida"</string>
<string name="description_target_search" msgid="3091587249776033139">"Otsing"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Lohistage üles: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -224,13 +233,16 @@
<!-- no translation found for zen_mode_notification_title:other (7388721375827338153) -->
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Puudutage kuvamiseks"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Mitte segada"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Veel %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Vähem kiireloomulised märguanded on allpool"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Avamiseks puudutage uuesti"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Lukustuse tühistamiseks pühkige üles"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Telefoni kasutamiseks pühkige paremale"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Kaamera kasutamiseks pühkige vasakule"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Kuni lülitate selle välja"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Külaline"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ külaline"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Üheks minutiks"</item>
<item quantity="other" msgid="6924190729213550991">"%d minutiks"</item>
@@ -239,4 +251,7 @@
<item quantity="one" msgid="3480040795582254384">"Üheks tunniks"</item>
<item quantity="other" msgid="5408537517529822157">"%d tunniks"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Akusäästja on sisse lülitatud"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Seadme jõudlust on vähendatud."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Ava akusäästja seaded"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 3ea2110..3595b6a 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"اعلانی موجود نیست"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"در حال انجام"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"اعلانها"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"شارژر را متصل کنید"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"باتری در حال کم شدن است."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"شارژ باتری کم است"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> باقیمانده است"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> باقی مانده است. ذخیره کننده باتری روشن است."</string>
<string name="invalid_charger" msgid="4549105996740522523">"شارژ USB پشتیبانی نمیشود.\nفقط از شارژر ارائه شده استفاده کنید."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"استفاده از باتری"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"شارژ با USB پشتیبانی نمیشود."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"فقط از شارژر ارائه شده استفاده کنید."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"تنظیمات"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"ذخیره کننده باتری شروع شود؟"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"شروع"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"شروع ذخیره کننده باتری"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"ذخیره کننده باتری برای کمک به بهبود عمر باتری شما، عملکرد دستگاهتان را کاهش میدهد.\n\nهنگامی که دستگاه شما به برق وصل است، ذخیره کننده باتری خاموش میشود."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"تنظیمات"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"حالت هواپیما"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"روشن."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"خاموش."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"متصل."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"در حال مرتبط شدن."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"بلوتوث ( <xliff:g id="NUMBER">%d</xliff:g> دستگاه)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"بلوتوث خاموش"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"روشنایی"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"چرخش خودکار"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"چرخش قفل شد"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"قفل شده در حالت عمودی"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"قفل شده در حالت افقی"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"چرخش اتوماتیک"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"چرخش قفل شد"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"عمودی"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"افقی"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"روش ورودی"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"مکان"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"مکان خاموش"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"متصل نیست"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"فرستادن صفحه"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"فرستادن صفحهنمایش"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"روشنایی"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"خودکار"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"برگردان رنگها"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"هیچ برنامه جدیدی موجود نیست"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"اطلاعات برنامه"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"جستجو"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"شارژ کامل شد"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"در حال شارژ شدن"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> مانده تا شارژ کامل شود"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"شارژ نمیشود"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ممکن است شبکه\nتحت نظارت باشد"</string>
<string name="description_target_search" msgid="3091587249776033139">"جستجو"</string>
<string name="description_direction_up" msgid="7169032478259485180">"لغزاندن به بالا برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"برای نمایش لمس کنید"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"مزاحم نشوید"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d بیشتر"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"اعلانهای کمتر فوری در زیر"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"برای باز کردن دوباره ضربه بزنید"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"برای باز کردن قفل سریع به بالا بکشید"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"برای تلفن انگشت را تند به سمت چپ بکشید"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"برای دوربین انگشت را تند به سمت راست بکشید"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"تا وقتی آن را خاموش کنید"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"در حال شارژ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"مهمان"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ مهمان"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"برای یک دقیقه"</item>
<item quantity="other" msgid="6924190729213550991">"برای %d دقیقه"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"برای یک ساعت"</item>
<item quantity="other" msgid="5408537517529822157">"برای %d ساعت"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"ذخیره کننده باتری روشن است."</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"عملکرد دستگاه کاهش یافته است."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"باز کردن تنظیمات ذخیره کننده باتری"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index eb68ea6..19b0f17 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ei ilmoituksia"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Käynnissä olevat"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ilmoitukset"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Kytke laturi"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Akun virta on vähissä."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Akku on vähissä"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> jäljellä"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> jäljellä. Virransäästö on käytössä."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-latausta ei tueta.\nKäytä laitteen mukana tullutta laturia."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Akun käyttö"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB-latausta ei tueta."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Käytä vain laitteen mukana toimitettua laturia."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Asetukset"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Käynnistetäänkö virransäästö?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Käynnistä"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Käynnistä virransäästö"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Virransäästötoiminto pidentää akun kestoa vähentämällä laitteen virrankulutusta.\n\nLaitteen kytkeminen virtalähteeseen poistaa virransäästön käytöstä."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Asetukset"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lentokonetila"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Käytössä."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Pois käytöstä."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Yhdistetty."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Yhdistetään."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> laitetta)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth pois käytöstä"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Kirkkaus"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automaattinen kääntö"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Kääntö lukittu"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Vaaka lukittu"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Pysty lukittu"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automaattinen kääntö"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Kääntö lukittu"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Pysty"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Vaaka"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Syöttötapa"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Sijainti"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Sijainti ei käytössä"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ei yhteyttä"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Lähetysnäyttö"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Lähetysnäyttö"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kirkkaus"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Käänteiset värit"</string>
@@ -213,10 +218,13 @@
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Jaettu yhteys"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Ilmoitukset"</string>
- <!-- no translation found for recents_empty_message (7883614615463619450) -->
- <skip />
+ <string name="recents_empty_message" msgid="7883614615463619450">"Ei viimeaikaisia sovelluksia"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Sovellustiedot"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"haku"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ladattu"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Ladataan"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> kunnes täynnä"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ei lataudu"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Verkkoa saatetaan\nvalvoa"</string>
<string name="description_target_search" msgid="3091587249776033139">"Haku"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Liu\'uta ylös ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -227,13 +235,18 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Näytä koskettamalla"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Älä häiritse"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d muuta"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Vähemmän kiireelliset ilmoitukset ovat alla"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Avaa napauttamalla uudelleen"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Avaa lukitus pyyhkäisemällä ylös"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Avaa puhelin pyyhkäisemällä oikealle"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Avaa kamera pyyhkäisemällä oikealle"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Kunnes poistat tämän käytöstä"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ladataan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kunnes täynnä)"</string>
+ <!-- no translation found for guest_nickname (8059989128963789678) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (4259024453643879653) -->
+ <skip />
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Minuutiksi"</item>
<item quantity="other" msgid="6924190729213550991">"%d minuutiksi"</item>
@@ -242,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Tunniksi"</item>
<item quantity="other" msgid="5408537517529822157">"%d tunniksi"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Virransäästö on käytössä"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Laitteen virrankulutusta vähennetään."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Avaa virransäästöasetukset"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 4c1df8c..03ac011 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Aucune notification"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En cours"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Brancher le chargeur"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Le niveau de la batterie est faible."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Pile faible"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restant(s)"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Il reste : <xliff:g id="NUMBER">%d%%</xliff:g>. La fonction Économie d\'énergie est activée."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Chargement USB non compatible.\nVous devez utiliser le chargeur fourni."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Utilisation de la batterie"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Le chargement par USB n\'est pas pris en charge."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Utilisez uniquement le chargeur fourni."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Paramètres"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Démarrer la fonction Économie d\'énergie?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Démarrer"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Démarrer la fonction Économie d\'énergie"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Pour vous aider à prolonger l\'autonomie de votre appareil, la fonction Économie d\'énergie réduit les performances de l\'appareil.\n\nElle se désactive lorsque l\'appareil est branché."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Paramètres"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode Avion"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Activé"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Désactivé"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Connecté"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Connexion."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1x"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"3G+"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> appareils)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"BLUETOOTH DÉSACTIVÉ"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Luminosité"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Rotation automatique"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotation verrouillée"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Verrouillé en mode portrait"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Verrouillé en mode paysage"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Rotation automatique"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotation verrouillée"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Portrait"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Paysage"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Mode de saisie"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Position"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Localisation désactivée"</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Non connecté"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Écran distant"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Écran de diffusion"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverser les couleurs"</string>
@@ -215,10 +220,13 @@
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Partage de connexion"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Point d\'accès sans fil"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notifications"</string>
- <!-- no translation found for recents_empty_message (7883614615463619450) -->
- <skip />
+ <string name="recents_empty_message" msgid="7883614615463619450">"Aucune application récente"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Détails de l\'application"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargée"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Charge en cours..."</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Chargée dans <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"N\'est pas en charge"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string>
<string name="description_target_search" msgid="3091587249776033139">"Recherche"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Faire glisser le doigt vers le haut : <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
@@ -229,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Touchez pour afficher la notification"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Ne pas déranger"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d autres"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Notifications moins urgentes affichées ci-dessous"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Touchez à nouveau pour ouvrir"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Glissez vers le haut pour déverrouiller"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Balayez l\'écran vers la droite pour accéder au téléphone"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Balayez l\'écran vers la gauche pour accéder à l\'appareil photo"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Jusqu\'à la désactivation"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours... (chargée à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Invité"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Ajouter un invité"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Pendant une minute"</item>
<item quantity="other" msgid="6924190729213550991">"Pendant %d minutes"</item>
@@ -244,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Pendant une heure"</item>
<item quantity="other" msgid="5408537517529822157">"Pendant %d heures"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"La fonction Économie d\'énergie est activée"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Les performances de l\'appareil sont réduites."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Ouvrir les paramètres d\'économie d\'énergie"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index bd709a0..fcad161 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Aucune notification"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En cours"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Brancher le chargeur"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Le niveau de la batterie est faible."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Batterie faible"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restant(s)"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Il reste <xliff:g id="NUMBER">%d%%</xliff:g>. L\'économiseur de batterie est activé."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Chargement USB non disponible.\nVous devez utiliser le chargeur fourni."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Utilisation de la batterie"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Chargeur USB non compatible."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Veuillez n\'utiliser que le chargeur fourni."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Paramètres"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Démarrer l\'économiseur de batterie ?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Démarrer"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Démarrer l\'économiseur de batterie"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Pour vous aider à prolonger l\'autonomie de la batterie, les performances de l\'appareil sont réduites.\n\nL\'économiseur de batterie est désactivé lorsque l\'appareil est branché."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Paramètres"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode Avion"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Activé"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Désactivé"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Connecté"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Connexion en cours…"</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1x"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> appareils)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth désactivé"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Luminosité"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Rotation auto"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotation bloquée"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Verrouillé en mode portrait"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Verrouillé en mode paysage"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Rotation automatique"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotation verrouillée"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Portrait"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Paysage"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Mode de saisie"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Localisation"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Localisation désactivée"</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Non connecté"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Caster l\'écran"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Caster l\'écran"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverser les couleurs"</string>
@@ -218,6 +223,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Aucune application récente"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informations sur l\'application"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargé"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"En charge"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Chargé dans <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"N\'est pas en charge"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string>
<string name="description_target_search" msgid="3091587249776033139">"Rechercher"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Faites glisser vers le haut pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -228,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Appuyer pour afficher"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Ne pas déranger"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"+ %d autres"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Notifications moins urgentes ci-dessous"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Appuyer à nouveau pour ouvrir"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Faire glisser pour déverrouiller"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Balayer l\'écran vers la droite pour accéder au téléphone"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Balayer l\'écran vers la gauche pour accéder à l\'appareil photo"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Jusqu\'à la désactivation"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours… (chargé à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Invité"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Ajouter un invité"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Pendant une minute"</item>
<item quantity="other" msgid="6924190729213550991">"Pendant %d minutes"</item>
@@ -243,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Pendant une heure"</item>
<item quantity="other" msgid="5408537517529822157">"Pendant %d heures"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"L\'économiseur de batterie est activé"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Les performances de l\'appareil sont réduites."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Ouvrir les paramètres de l\'économiseur de batterie"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index d6b6d6a..c33c1d5 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"कोई सूचना नहीं"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ऑनगोइंग"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"सूचनाएं"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"चार्जर कनेक्ट करें"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"बैटरी कम हो रही है."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"बैटरी कम है"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> शेष"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> शेष. बैटरी सेवर चालू है."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB चार्जिंग समर्थित नहीं है.\nकेवल आपूर्ति किए गए चार्जर का उपयोग करें."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"बैटरी उपयोग"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB चार्जिंग समर्थित नहीं है."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"केवल आपूर्ति किए गए चार्जर का उपयोग करें."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"सेटिंग"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"बैटरी सेवर प्रारंभ करें?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"प्रारंभ करें"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"बैटरी सेवर प्रारंभ करें"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"बैटरी का जीवनकाल बेहतर बनाने में सहायता के लिए, बैटरी सेवर आपके उपकरण के प्रदर्शन को कम कर देगा.\n\nआपका उपकरण प्लग किए जाने पर बैटरी सेवर अक्षम हो जाएगा."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिंग"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"हवाई जहाज मोड"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"चालू."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"बंद."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"कनेक्ट है."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"कनेक्ट हो रहा है."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> उपकरण)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth बंद"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"स्क्रीन की रोशनी"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"स्वत: रोटेट"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"रोटेशन लॉक किया गया"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"पोर्ट्रेट पर लॉक किया गया"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"भू-दृश्य पर लॉक किया गया"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"स्वत: घुमाएं"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"घुमाना लॉक किया गया"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"पोर्ट्रेट"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"लैंडस्केप"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"इनपुट विधि"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"स्थान"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"स्थान बंद"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"कनेक्ट नहीं है"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"स्क्रीन कास्ट करें"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"स्क्रीन कास्ट करें"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"स्क्रीन की रोशनी"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वत:"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"रंग उलटें"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"कोई हाल ही का ऐप्स नहीं"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"एप्लिकेशन जानकारी"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"खोज"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज हो गई है"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"चार्ज हो रही है"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"पूर्ण होने में <xliff:g id="CHARGING_TIME">%s</xliff:g> शेष"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"चार्ज नहीं हो रही है"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"नेटवर्क को\nमॉनीटर किया जा सकता है"</string>
<string name="description_target_search" msgid="3091587249776033139">"खोजें"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए ऊपर स्लाइड करें."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"दिखाने के लिए स्पर्श करें"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"परेशान न करें"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d और"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"कम अत्यावश्यक सूचनाएं नीचे दी गई हैं"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"खोलने के लिए पुन: टैप करें"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"अनलॉक करने के लिए ऊपर स्वाइप करें"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"फ़ोन के लिए दाएं स्वाइप करें"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"कैमरे के लिए बाएं स्वाइप करें"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"जब तक आप इसे बंद नहीं कर देते"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हो रहा है (पूर्ण होने में <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> शेष)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"अतिथि"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ अतिथि"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"एक मिनट के लिए"</item>
<item quantity="other" msgid="6924190729213550991">"%d मिनट के लिए"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"एक घंटे के लिए"</item>
<item quantity="other" msgid="5408537517529822157">"%d घंटे के लिए"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"बैटरी सेवर चालू है"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"उपकरण का प्रदर्शन कम हो गया है."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"बैटरी सेवर सेटिंग चालू करें"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 79d7003..024be82 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Bez obavijesti"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"U tijeku"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obavijesti"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Priključite punjač"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Baterija će uskoro biti potrošena."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Niska razina baterije"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> preostalo"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Preostalo je <xliff:g id="NUMBER">%d%%</xliff:g>. Štednja baterije je uključena."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB punjenje nije podržano.\nUpotrijebite samo priloženi punjač."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Iskorištenost baterije"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Punjenje putem USB-a nije podržano."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Upotrebljavajte samo priloženi punjač."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Postavke"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Želite li pokrenuti štednju baterije?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Kreni"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Pokretanje štednje baterije"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Da bi baterija trajala dulje, Štednja baterije smanjit će intenzitet rada uređaja.\n\nŠtednja baterije onemogućit će se kada je uređaj priključen."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Postavke"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Način rada u zrakoplovu"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Uključeno."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Isključeno."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Povezano."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Povezivanje."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (broj uređaja: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth isključen"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Svjetlina"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automatska rotacija"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotacija zaključana"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Blokirano u portretnom prikazu"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Blokirano u pejzažnom prikazu"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatsko izmjenjivanje"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Izmjenjivanje je zaključano"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Okomito"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Vodoravno"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Način unosa"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Lokacija"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Lokacija je isključena"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nije povezano"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Emitiranje zaslona"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Emitirani zaslon"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Svjetlina"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATSKI"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Preokreni boje"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Nema nedavnih aplikacija"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjeno"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Punjenje"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do napunjenosti"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ne puni se"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mreža se\nmožda prati"</string>
<string name="description_target_search" msgid="3091587249776033139">"Pretraživanje"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Kliznite prema gore za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Dodirnite za prikaz"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Ne ometaj"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Još %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Manje hitne obavijesti pri dnu"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Dodirnite opet za otvaranje"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Prijeđite prstom prema gore za otključavanje"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Prijeđite prstom udesno za telefon"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Prijeđite prstom ulijevo za fotoaparat"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Dok ne isključite"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Gost"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ gost"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Jednu minutu"</item>
<item quantity="other" msgid="6924190729213550991">"%d min"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Jedan sat"</item>
<item quantity="other" msgid="5408537517529822157">"%d h"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Štednja baterije je uključena"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Uređaj radi smanjenim intenzitetom."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otvaranje postavki štednje baterije"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 915f5eb..deeb7f4 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nincs értesítés"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Folyamatban van"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Értesítések"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Csatlakoztassa a töltőt"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Az akkufeszültség alacsony."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Alacsony az energiaszint"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> maradt"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> maradt. Az Akkumulátorkímélő mód bekapcsol."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Az USB-n keresztüli töltés nincs támogatva.\nHasználja a kapott töltőt."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Akkumulátorhasználat"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Az USB-n keresztüli töltés nem támogatott."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Kizárólag a tartozékként kapott töltőt használja."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Beállítások"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Elindítja az Akkumulátorkímélő módot?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Indítás"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Akkumulátorkímélő mód indítása"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Az Akkumulátorkímélő mód csökkenti az eszköz teljesítményét, hogy növelje az akkumulátor üzemidejét.\n\nAz eszköz töltésekor az Akkumulátorkímélő üzemmód kikapcsol."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Beállítások"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Repülőgép üzemmód"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Bekapcsolva."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Kikapcsolva."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Csatlakoztatva."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Csatlakozás."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> eszköz)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth kikapcsolva"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Fényerő"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automatikus forgatás"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Forgatás zárolva"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Álló nézet zárolva"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Fekvő nézet zárolva"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatikus elforgatás"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Elforgatás zárolva"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Álló"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Fekvő"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Beviteli módszer"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Tartózkodási hely"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Hely kikapcsolva"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nincs kapcsolat"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Képernyő tartalmának átküldése"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Képernyőtartalom átküldése"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Fényerő"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"automatikus"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Színek invertálása"</string>
@@ -213,9 +218,13 @@
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Megosztás"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Értesítések"</string>
- <string name="recents_empty_message" msgid="7883614615463619450">"Nincs újabb alkalmazás"</string>
+ <string name="recents_empty_message" msgid="7883614615463619450">"Nincsenek nemrég használt alkalmazások"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Az alkalmazás adatai"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Feltöltve"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Töltés"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> a teljes töltöttségig"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nem töltődik"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Lehet, hogy a\nhálózat felügyelt"</string>
<string name="description_target_search" msgid="3091587249776033139">"Keresés"</string>
<string name="description_direction_up" msgid="7169032478259485180">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa felfelé."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"A megtekintéshez érintse meg"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Ne zavarjanak"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d további"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"A kevésbé sürgős értesítések lentebb vannak"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Koppintson rá ismét a megnyitáshoz"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Húzza felfelé az ujját a feloldáshoz"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"A telefon eléréséhez csúsztassa ujját jobbra"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"A fényképezőgép eléréséhez csúsztassa ujját balra"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Amíg ki nem kapcsolja ezt"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Vendég"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ vendég"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Egy percen át"</item>
<item quantity="other" msgid="6924190729213550991">"%d percen át"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Egy órán át"</item>
<item quantity="other" msgid="5408537517529822157">"%d órán át"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Akkumulátorkímélő mód bekapcsolva"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Az eszköz teljesítménye lecsökkentve."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Akkumulátorkímélő mód beállításainak megnyitása"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index ca327d8..4424338 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ծանուցումներ չկան"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Ընթացիկ"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ծանուցումներ"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Միացրեք լիցքավորիչը"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Մարտկոցը լիցքաթափվում է:"</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Մարտկոցը լիցքաթափվում է"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"մնում է <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Մնաց <xliff:g id="NUMBER">%d%%</xliff:g>: Մարտկոցի տնտեսումը միացված է:"</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB լիցքավորումը չի աջակցվում:\nՕգտվեք միայն գործող լիցքավորիչից:"</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Մարտկոցի օգտագործումը"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB լիցքավորումը չի աջակցվում:"</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Օգտագործեք միայն մատակարարի տրամադրած լիցքավորիչը:"</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Կարգավորումներ"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Գործարկե՞լ մարտկոցի տնտեսումը:"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Մեկնարկել"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Գործարկել մարտկոցի տնտեսումը"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Մարտկոցի տնտեսումը կնվազեցնի ձեր սարքի կատարողականը՝ մարտկոցն ավելի երկար օգտագործելու համար:\n\nՄարտկոցի տնտեսումը կանջատվի, հենց սարքը միացնեք հոսանքի աղբյուրին:"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Կարգավորումներ"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Ինքնաթիռային ռեժիմ"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Միացված է:"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Անջատված է:"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Միացված է:"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Միանում է:"</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> սարք)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth-ն անջատված է"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Պայծառություն"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Ինքնապտտում"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Պտտումը կողպված է"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Միայն ուղղաձիգ"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Միայն հորիզոնական"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Ինքնապտտում"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Պտտումը կողպված է"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Դիմանկար"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Լանդշաֆտ"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Մուտքագրման եղանակը"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Տեղադրություն"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Անջատել տեղադրությունը"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Միացված չէ"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Հեռակա էկրան"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Հեռակա էկրան"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Պայծառություն"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"Ինքնաշխատ"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Շրջել գույները"</string>
@@ -213,10 +218,13 @@
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Միացում"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Թեժ կետ"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Ծանուցումներ"</string>
- <!-- no translation found for recents_empty_message (7883614615463619450) -->
- <skip />
+ <string name="recents_empty_message" msgid="7883614615463619450">"Նոր հավելվածներ չկան"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Հավելվածի մասին"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"որոնել"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Լիցքավորված է"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Լիցքավորվում է"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Լրիվ լիցքավորմանը մնաց <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Չի լիցքավորվում"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ցանցը կարող է\nվերահսկվել"</string>
<string name="description_target_search" msgid="3091587249776033139">"Որոնել"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Սահեցրեք վերև <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
@@ -227,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Հպեք՝ ցուցադրելու համար"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Չխանգարել"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Եվս %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Պակաս հրատապ ծանուցումները ստորև"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Կրկին հպեք՝ բացելու համար"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Սահեցրեք վերև` ապակողպելու համար"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Հեռախոսի համար սահեցրեք աջ"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Խցիկի համար սահեցրեք ձախ"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Քանի դեռ չեք անջատել"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> մինչև լրիվ լիցքավորումը)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Հյուր"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Հյուր"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Մեկ րոպե"</item>
<item quantity="other" msgid="6924190729213550991">"%d րոպե"</item>
@@ -242,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Մեկ ժամ"</item>
<item quantity="other" msgid="5408537517529822157">"%d ժամ"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Մարտկոցի տնտեսումը միացված է"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Սարքի կատարողականը նվազեցված է:"</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Բացել մարտկոցի տնտեսման կարգավորումները"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 48c9a6d..5dbd490 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Tidak ada pemberitahuan"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Berkelanjutan"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Pemberitahuan"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Hubungkan pengisi daya"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Baterai semakin lemah."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Baterai lemah"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> tersisa"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Tersisa <xliff:g id="NUMBER">%d%%</xliff:g>. Penghemat baterai aktif."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Pengisian daya USB tidak didukung.\nGunakan hanya pengisi daya yang disediakan."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Penggunaan baterai"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Pengisian daya USB tidak didukung."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Hanya gunakan pengisi daya yang disediakan."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Setelan"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Mulai penghemat baterai?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Mulai"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Mulai penghemat baterai"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Untuk membantu meningkatkan masa pakai baterai, Penghemat baterai akan mengurangi kinerja perangkat Anda.\n\nPenghemat baterai akan dinonaktifkan saat perangkat dihubungkan dengan sumber daya."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Setelan"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode pesawat"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Aktif."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Nonaktif."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Tersambung."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Menyambung."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Perangkat)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Mati"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Kecerahan"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Rotasi Otomatis"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotasi Dikunci"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Terkunci ke Potret"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Terkunci ke Lanskap"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Rotasi otomatis"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotasi terkunci"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Potret"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Lanskap"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Metode Masukan"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Lokasi"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Lokasi Mati"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Tidak Tersambung"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Layar Transmisi"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Layar transmisi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATIS"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inversi warna"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Tidak ada aplikasi terkini"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Info Aplikasi"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"telusuri"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Terisi"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Mengisi daya"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> sampai penuh"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Tidak mengisi daya"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Jaringan bisa\ndiawasi"</string>
<string name="description_target_search" msgid="3091587249776033139">"Telusuri"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Geser ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Sentuh untuk menampilkan"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Jangan ganggu"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d lainnya"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Pemberitahuan kurang darurat di bawah"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Ketuk lagi untuk membuka"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Gesek ke atas untuk membuka kunci"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Gesek ke kanan untuk menelepon"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Gesek ke kiri untuk kamera"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Hingga Anda menonaktifkan ini"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengisi daya (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Tamu"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Tamu"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Selama satu menit"</item>
<item quantity="other" msgid="6924190729213550991">"Selama %d menit"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Selama satu jam"</item>
<item quantity="other" msgid="5408537517529822157">"Selama %d jam"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Penghemat baterai aktif"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Kinerja perangkat dikurangi."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Buka setelan penghemat baterai"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 8653c8f..9f1722d 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nessuna notifica"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"In corso"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifiche"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Collega il caricabatterie"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteria quasi scarica."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Batteria quasi scarica"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> rimanente"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> rimanente. La funzione Risparmio batteria è attiva."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Ricarica tramite USB non supportata.\nUtilizza solo il caricatore in dotazione."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Utilizzo batteria"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Ricarica tramite USB non supportata."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Utilizza solo il caricabatterie fornito in dotazione."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Impostazioni"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Avviare risparmio batteria?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Inizia"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Avvia risparmio batteria"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Per aumentare la durata della batteria, Risparmio batteria riduce le prestazioni del tuo dispositivo.\n\nRisparmio batteria si disattiva quando il dispositivo è collegato alla corrente."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Impostazioni"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modalità aereo"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"ON"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"OFF"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Connesso."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Connessione in corso."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivi)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth spento"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Luminosità"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Rotazione autom."</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotazione bloccata"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Bloccato in verticale"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Bloccato in orizzontale"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Rotazione automatica"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotazione bloccata"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Verticale"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Orizzontale"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Metodo di immissione"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Geolocalizz."</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Geolocalizz. non attiva"</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Non connesso"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Trasmetti schermo"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Trasmetti schermo"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosità"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverti colori"</string>
@@ -218,6 +223,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Nessuna app recente"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informazioni sull\'applicazione"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carica"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"In carica"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> al termine della carica"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Non in carica"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La rete potrebbe\nessere monitorata"</string>
<string name="description_target_search" msgid="3091587249776033139">"Ricerca"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Su per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -228,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Tocca per visualizzare"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Non disturbare"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Altre %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Notifiche meno urgenti in basso"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Tocca ancora per aprire"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Scorri verso l\'alto per sbloccare"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Scorri verso destra per accedere al telefono"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Scorri verso sinistra per accedere alla fotocamera"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Fino alla disattivazione"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"In carica (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Ospite"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ ospite"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Per un minuto"</item>
<item quantity="other" msgid="6924190729213550991">"Per %d minuti"</item>
@@ -243,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Per un\'ora"</item>
<item quantity="other" msgid="5408537517529822157">"Per %d ore"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Risparmio batteria attivo"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Le prestazioni del dispositivo sono ridotte."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Apri impostazioni risparmio batteria"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 3279bc1..5b68451 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"אין התראות"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"מתמשך"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"התראות"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"חבר מטען"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"הסוללה נחלשת."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"עוצמת הסוללה נמוכה"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"נותרו <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"נותרו <xliff:g id="NUMBER">%d%%</xliff:g>. תכונת \'חיסכון בסוללה\' פועלת."</string>
<string name="invalid_charger" msgid="4549105996740522523">"טעינה באמצעות USB אינה נתמכת.\nהשתמש אך ורק במטען שסופק."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"צריכת סוללה"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"טעינה בחיבור USB אינה נתמכת."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"השתמש רק במטען שסופק."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"הגדרות"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"האם להפעיל את \'חיסכון בסוללה\'?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"התחל"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"הפעל את \'חיסכון בסוללה\'"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"כדי לעזור בהארכת חיי הסוללה, תכונת \'חיסכון בסוללה\' תצמצם את פעילות המכשיר.\n\nתכונת \'חיסכון בסוללה\' תושבת כשהמכשיר יחובר לחשמל."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"הגדרות"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"מצב טיסה"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"פועל."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"כבוי."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"מחובר."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"מתחבר."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> מכשירים)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth מופסק"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"בהירות"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"סיבוב אוטומטי"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"סיבוב נעול"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"נעול במצב הצגה לאורך"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"נעול במצב הצגה לרוחב"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"סיבוב אוטומטי"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"סיבוב נעול"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"לאורך"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"לרוחב"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"שיטת קלט"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"מיקום"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"מיקום כבוי"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"לא מחובר"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"העבר מסך"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"העבר מסך"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"בהירות"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"אוטומטי"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"הפוך צבעים"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"אין אפליקציות אחרונות"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"מידע על האפליקציה"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"חפש"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"טעון"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"טוען"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> עד למילוי"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"לא בטעינה"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ייתכן שהרשת\nמנוטרת"</string>
<string name="description_target_search" msgid="3091587249776033139">"חיפוש"</string>
<string name="description_direction_up" msgid="7169032478259485180">"הסט למעלה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"גע כדי להציג"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"נא לא להפריע"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"עוד %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"הודעות בדחיפות נמוכה יותר בהמשך"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"הקש שוב כדי לפתוח"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"החלק מעלה כדי לבטל את הנעילה"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"החלק ימינה להפעלת הטלפון"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"החלק שמאלה להפעלת המצלמה"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"עד שתכבה"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"טוען (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד לסיום)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"אורח"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ אורח"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"למשך דקה אחת"</item>
<item quantity="other" msgid="6924190729213550991">"למשך %d דקות"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"למשך שעה אחת"</item>
<item quantity="other" msgid="5408537517529822157">"למשך %d שעות"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"תכונת \'חיסכון בסוללה\' פועלת"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"פעילות המכשיר צומצמה."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"פתח את ההגדרות של \'חיסכון בסוללה\'"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index a1f7b5e..6ebd5c7 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"通知なし"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"実行中"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"充電してください"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"電池が残り少なくなっています。"</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"電池残量が少なくなっています"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"残り<xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"残量が<xliff:g id="NUMBER">%d%%</xliff:g>です。バッテリーセーバーはONです。"</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB充電には対応していません。\n付属の充電器をお使いください。"</string>
- <string name="battery_low_why" msgid="7279169609518386372">"電池使用量"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB充電には対応していません。"</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"専用の充電器のみを使用してください。"</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"設定"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"バッテリーセーバーを開始しますか?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"開始"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"バッテリーセーバーを開始"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを制限します。\n\n端末が電源に接続されているときはバッテリーセーバーが無効になります。"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"機内モード"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"ON"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"OFF"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"接続済みです。"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"接続しています。"</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth(端末数<xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth OFF"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"画面の明るさ"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"自動回転"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"画面の向きをロック"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"縦向きにロック済み"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"横向きにロック済み"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"自動回転"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"画面の向きをロック"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"縦向き"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"横向き"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"入力方法"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"現在地"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"現在地OFF"</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"接続されていません"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"画面のキャスト"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"画面のキャスト"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"画面の明るさ"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"色を反転"</string>
@@ -218,6 +223,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"最近使ったアプリはありません"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"アプリ情報"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"検索"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"充電が完了しました"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電しています"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"充電完了まで<xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"充電していません"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ネットワークが監視される\n場合があります"</string>
<string name="description_target_search" msgid="3091587249776033139">"検索します"</string>
<string name="description_direction_up" msgid="7169032478259485180">"上にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
@@ -228,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"表示するにはタップします"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"通知を非表示"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"他%d件"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"緊急度の低い通知を下に表示"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"開くにはもう一度タップしてください"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"ロック解除するには上にスワイプしてください"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"右にスワイプして電話を表示"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"左にスワイプしてカメラを表示"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"ユーザーがOFFにするまで"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中(フルになるまで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"ゲスト"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ ゲスト"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"1分"</item>
<item quantity="other" msgid="6924190729213550991">"%d分"</item>
@@ -243,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"1時間"</item>
<item quantity="other" msgid="5408537517529822157">"%d時間"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"バッテリーセーバーがON"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"端末のパフォーマンスが制限されています。"</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"バッテリーセーバーの設定を開く"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index a1862da..8f1f30a 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"შეტყობინებები არ არის."</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"მიმდინარე"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"შეტყობინებები"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"შეაერთეთ დამტენი."</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"ბატარეა ჯდება."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"ბატარეა იწურება"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"დარჩენილია <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"დარჩენილია <xliff:g id="NUMBER">%d%%</xliff:g>. გააქტიურებულია ბატარეის დამზოგი."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-ით დატენვა არ არის მხარდაჭერილი.\nგამოიყენეთ მხოლოდ ელექტრო-დამტენი."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"ელემენტის გამოყენება"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB დატენვა მხარდაჭერილი არ არის."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"გამოიყენეთ მხოლოდ მოყოლილი დამტენი."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"პარამეტრები"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"გსურთ ბატარეის დამზოგის დაწყება?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"დაწყება"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"ბატარეის დამზოგის დაწყება"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"ბატარეის მოქმედების გასახანგრძლივებლად, ბატარეის დამზოგი შეამცირებს თქვენი მოწყობილობის წარმადობას.\n\nბატარეის დამზოგი გამოირთვება, როდესაც მოწყობილობას ელკვებაზე მიაერთებთ."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"პარამეტრები"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"თვითმფრინავის რეჟიმი"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"ჩართული"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"გამორთულია."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"დაკავშირებულია."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"უკავშირდება."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> მოწყობილობა)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth გამორთულია"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"სიკაშკაშე"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"ავტო მობრუნება"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"როტაციის ჩაკეტვა"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"პორტრეტზე ჩაკეტილი"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"ლანდშაფტზე ჩაკეტილი"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"ავტოროტაცია"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"როტაცია ჩაკეტილია"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"პორტრეტი"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"პეიზაჟის რეჟიმი"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"შეყვანის მეთოდი"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"მდებარეობა"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"მდებარეობა გამორთულია"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"არ არის დაკავშირებული."</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Cast Screen"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"ეკრანის გადაცემა"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"განათება"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ავტომატურად"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"ფერების შებრუნება"</string>
@@ -213,10 +218,13 @@
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"მოდემის რეჟიმი"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"წვდომის წერტილი"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"შეტყობინებები"</string>
- <!-- no translation found for recents_empty_message (7883614615463619450) -->
- <skip />
+ <string name="recents_empty_message" msgid="7883614615463619450">"ბოლო აპები არ არის"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"აპლიკაციის შესახებ"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ძიება"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"დატენილია"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"მიმდინარეობს დატენვა"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> სრულად დატენვამდე"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"არ იტენება"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"შესაძლოა ქსელზე\nმონიტორინგი ხორციელდებოდეს"</string>
<string name="description_target_search" msgid="3091587249776033139">"ძიება"</string>
<string name="description_direction_up" msgid="7169032478259485180">"გაასრიალეთ ზემოთ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string>
@@ -227,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"შეეხეთ საჩვენებლად"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"არ შემაწუხოთ"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d სხვა"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"ქვემოთ მითითებულია ნაკლებად სასწრაფო შეტყობინებები"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"შეეხეთ ისევ გასახსნელად"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"გაასრიალეთ ზევით განსაბლოკად"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"გადაფურცლეთ მარჯვნივ ტელეფონისთვის"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"კამერისთვის მარცხენა შენაცვლება"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"სანამ ამას გამორთავდეთ"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>-ის შეცვლა დასრულებამდე)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"სტუმარი"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ სტუმარი"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"ერთი წუთით"</item>
<item quantity="other" msgid="6924190729213550991">"%d წუთით"</item>
@@ -242,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"ერთი საათით"</item>
<item quantity="other" msgid="5408537517529822157">"%d საათით"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"ბატარეის დამზოგი ჩართულია"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"მოწყობილობის წარმადობა შემცირებულია."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ბატარეის დამზოგის პარამეტრების გახსნა"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 3f5b844..88d9b64 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"គ្មានការជូនដំណឹង"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"បន្ត"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"ការជូនដំណឹង"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"ភ្ជាប់ឧបករណ៍បញ្ចូលថ្ម"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"ជិតអស់ថ្មហើយ។"</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"ជិតអស់ថ្មហើយ"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"នៅសល់ <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"នៅសល់ <xliff:g id="NUMBER">%d%%</xliff:g> ។ កម្មវិធីសន្សំថ្មគឺបើក។"</string>
<string name="invalid_charger" msgid="4549105996740522523">"មិនគាំទ្រការបញ្ចូលតាមយូអេសប៊ី។\nប្រើតែឧបករណ៍បញ្ចូលថ្មដែលបានផ្ដល់។"</string>
- <string name="battery_low_why" msgid="7279169609518386372">"ការប្រើថ្ម"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"មិនគាំទ្រការបញ្ចូលថ្មតាមយូអេសប៊ីទេ។"</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"ប្រើតែឧបករណ៍បញ្ចូលថ្មដែលបានផ្ដល់ឲ្យ។"</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"ការកំណត់"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"ចាប់ផ្ដើមកម្មវិធីសន្សំថ្ម?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"ចាប់ផ្ដើម"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"ចាប់ផ្ដើមកម្មវិធីសន្សំថ្ម"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"ដើម្បីជួយបង្កើនអាយុកាលថ្ម កម្មវិធីសន្សំថ្មនឹងកាត់បន្ថយការអនុវត្តនៃឧបករណ៍របស់អ្នក។\n\nកម្មវិធីសន្សំថ្មនឹងបិទនៅពេលឧបករណ៍របស់អ្នកត្រូវបានដោតបញ្ចូលថ្ម។"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ការកំណត់"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"វ៉ាយហ្វាយ"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"ពេលជិះយន្តហោះ"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"បើក។"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"បិទ"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"បានតភ្ជាប់។"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"ការភ្ជាប់។"</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ប៊្លូធូស (ឧបករណ៍ <xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ប៊្លូធូសបានបិទ"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"ពន្លឺ"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"បង្វិលស្វ័យប្រវត្តិ"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"បានចាក់សោការបង្វិល"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"ចាក់សោបញ្ឈរ"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"ចាក់សោផ្ដេក"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"បង្វិលស្វ័យប្រវត្តិ"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"បានចាក់សោការបង្វិល"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"បញ្ឈរ"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"ទេសភាព"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"វិធីសាស្ត្របញ្ចូល"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"ទីតាំង"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"ទីតាំងបានបិទ"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"មិនបានតភ្ជាប់"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"គ្មានបណ្ដាញ"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"វ៉ាយហ្វាយបានបិទ"</string>
- <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"ចាត់ថ្នាក់អេក្រង់"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"ចាត់ថ្នាក់អេក្រង់"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ពន្លឺ"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ស្វ័យប្រវត្តិ"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"ដាក់បញ្ច្រាសពណ៌"</string>
@@ -213,10 +218,13 @@
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"ការភ្ជាប់"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"ហតស្ប៉ត"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"ការជូនដំណឹង"</string>
- <!-- no translation found for recents_empty_message (7883614615463619450) -->
- <skip />
+ <string name="recents_empty_message" msgid="7883614615463619450">"មិនមានកម្មវិធីថ្មីៗ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ព័ត៌មានកម្មវិធី"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ស្វែងរក"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"បានបញ្ចូលថ្ម"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"កំពុងបញ្ចូលថ្ម"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> រហូតដល់ពេញ"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"មិនកំពុងបញ្ចូលថ្ម"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញអាច\nត្រូវបានត្រួតពិនិត្យ"</string>
<string name="description_target_search" msgid="3091587249776033139">"ស្វែងរក"</string>
<string name="description_direction_up" msgid="7169032478259485180">"រុញឡើងលើដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
@@ -227,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"ប៉ះដើម្បីបង្ហាញ"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"កុំរំខាន"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d ទៀត"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"ការជូនដំណឹងមិនសូវបន្ទាន់ខាងក្រោម"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"ប៉ះម្ដងទៀត ដើម្បីបើក"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"អូសឡើងលើ ដើម្បីដោះសោ"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"អូសទៅស្ដាំដើម្បីបើកទូរស័ព្ទ"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"អូសទៅឆ្វេងដើម្បីប្រើម៉ាស៊ីនថត"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"រហូតដល់ពេលអ្នកបិទវា"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"កំពុងបញ្ចូលថ្ម (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើបពេញ)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"ភ្ញៀវ"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ ភ្ញៀវ"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"សម្រាប់មួយនាទី"</item>
<item quantity="other" msgid="6924190729213550991">"សម្រាប់ %d នាទី"</item>
@@ -242,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"សម្រាប់មួយម៉ោង"</item>
<item quantity="other" msgid="5408537517529822157">"សម្រាប់ %d ម៉ោង"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"កម្មវិធីសន្សំថ្មគឺបើក"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"ការអនុវត្តឧបករណ៍ត្រូវបានកាត់បន្ថយ។"</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"បើកការកំណត់កម្មវិធីសន្សំថ្ម"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 4772e54..0ffb4b8 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -32,11 +32,19 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"알림 없음"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"진행 중"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"알림"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"충전기를 연결하세요."</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"배터리가 얼마 남지 않았습니다."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"배터리 부족"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> 남음"</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for battery_low_percent_format_saver_started (6534746636002666456) -->
+ <skip />
<string name="invalid_charger" msgid="4549105996740522523">"USB 충전이 지원되지 않습니다.\n제공된 충전기만 사용하세요."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"배터리 사용량"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB 충전은 지원되지 않습니다."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"제공된 충전기만 사용하세요."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"설정"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"배터리 세이버를 시작할까요?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"시작"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"배터리 세이버 시작"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"배터리 세이버는 기기의 성능을 저하시켜 배터리 수명을 늘립니다.\n\n기기에 전원이 연결되면 배터리 세이버는 사용 중지됩니다."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"설정"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"비행기 모드"</string>
@@ -120,8 +128,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"사용"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"사용 안함"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"연결됨"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"연결 중..."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"블루투스(<xliff:g id="NUMBER">%d</xliff:g>개의 기기)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"블루투스 사용 안함"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"밝기"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"자동 회전"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"회전 잠금"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"세로 모드로 고정됨"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"가로 모드로 고정됨"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"자동 회전"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"방향 고정"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"세로"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"가로"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"입력 방법"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"위치"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"위치 사용 중지"</string>
@@ -204,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"연결되어 있지 않음"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"화면 전송"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"화면 전송"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"밝기"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"자동"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"색상 반전"</string>
@@ -216,6 +223,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"최근에 사용한 앱 없음"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"애플리케이션 정보"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"검색"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"충전됨"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"충전 중"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"완충까지 <xliff:g id="CHARGING_TIME">%s</xliff:g> 남음"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"충전 안함"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"네트워크가\n모니터링될 수 있음"</string>
<string name="description_target_search" msgid="3091587249776033139">"검색"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 위로 슬라이드"</string>
@@ -226,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"표시하려면 터치"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"알림 일시중지"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d개 더보기"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"아래에 덜 급한 알림 표시"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"다시 탭하여 열기"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"위로 스와이프하여 잠금 해제"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"전화 기능을 사용하려면 오른쪽으로 스와이프하세요."</string>
+ <string name="camera_hint" msgid="5241441720959174226">"카메라를 사용하려면 왼쪽으로 스와이프하세요."</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"이 기능을 사용 중지할 때까지"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"손님"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"새 손님 추가"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"1분 동안"</item>
<item quantity="other" msgid="6924190729213550991">"%d분 동안"</item>
@@ -241,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"1시간 동안"</item>
<item quantity="other" msgid="5408537517529822157">"%d시간 동안"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"배터리 세이버 사용 중"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"기기의 성능이 저하됩니다."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"배터리 세이버 설정 열기"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index d5117a9..3688c57 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"ບໍ່ມີການແຈ້ງເຕືອນ"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ດຳເນີນຢູ່"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"ການແຈ້ງເຕືອນ"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"ເຊື່ອມຕໍ່ສາຍສາກ"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"ແບັດເຕີຣີເຫຼືອໜ້ອຍແລ້ວ."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"ແບັດເຕີຣີເຫຼືອໜ້ອຍ"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"ຍັງເຫຼືອອີກ <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"ຍັງເຫຼືອ <xliff:g id="NUMBER">%d%%</xliff:g>. ເປີດນຳໃຊ້ໂຕປະຢັດແບັດເຕີຣີຢູ່."</string>
<string name="invalid_charger" msgid="4549105996740522523">"ບໍ່ຮອງຮັບການສາກໄຟດ້ວຍ USB.\nຕ້ອງໃຊ້ສະເພາະເຄື່ອງສາກທີ່ແຖມມານຳເທົ່ານັ້ນ."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"ການນຳໃຊ້ແບັດເຕີຣີ"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"ບໍ່ຮອງຮັບການສາກຜ່ານ USB."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"ໃຊ້ສະເພາະສາຍສາກທີ່ມາກັບເຄື່ອງ."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"ການຕັ້ງຄ່າ"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"ເລີ່ມໂຕປະຢັດແບັດເຕີຣີບໍ?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"ເລີ່ມ"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"ເລີ່ມໂຕປະຢັດແບັດເຕີຣີ"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"ເພື່ອຊ່ວຍຢືດອາຍຸແບັດເຕີຣີ, ໂຕປະຢັດແບັດເຕີຣີຈະຫຼຸດປະສິດທິພາບຂອງອຸປະກອນທ່ານລົງ.\n\nໂຕປະຢັດແບັດເຕີຣີຈະຖືກປິດການນຳໃຊ້ໂດຍອັດຕະໂນມັດເມື່ອທ່ານສຽບສາຍສາກອຸປະກອນຂອງທ່ານ."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ການຕັ້ງຄ່າ"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"ໂໝດເທິງຍົນ"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"ເປີດ."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"ປິດ."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"ເຊື່ອມຕໍ່ແລ້ວ."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"ກຳລັງເຊື່ອມຕໍ່."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> ອຸປະກອນ)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth ປິດ"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"ຄວາມສະຫວ່າງ"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"ໝຸນໜ້າຈໍອັດຕະໂນມັດ"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"ລັອກການປ່ຽນລວງ"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"ລັອກເປັນຮູບລວງຕັ້ງ"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"ລັອກເປັນຮູບລວງນອນ"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"ໝຸນອັດຕະໂນມັດ"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"ລັອກການໝຸນຈໍແລ້ວ"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"ລວງຕັ້ງ"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"ລວງນອນ"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"ວິທີການປ້ອນຂໍ້ມູນ"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"ສະຖານທີ່"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"ຂໍ້ມູນສະຖານທີ່ປິດຢູ່"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"ບໍ່ໄດ້ເຊື່ອມຕໍ່"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"ດຶງໜ້າຈໍ"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"ສົ່ງສັນຍານພາບ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ຄວາມແຈ້ງ"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ອັດຕະໂນມັດ"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"ສະລັບສີ"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"ບໍ່ມີແອັບຯທີ່ຫາກໍໃຊ້"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ຂໍ້ມູນແອັບພລິເຄຊັນ"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ສາກເຕັມແລ້ວ."</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"ກຳລັງສາກໄຟ"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ຈຶ່ງຈະເຕັມ"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"ບໍ່ໄດ້ສາກໄຟ"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ເຄືອຄ່າຍອາດ\nຖືກຕິດຕາມ"</string>
<string name="description_target_search" msgid="3091587249776033139">"ຊອກຫາ"</string>
<string name="description_direction_up" msgid="7169032478259485180">"ເລື່ອນຂຶ້ນເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"ແຕະເພື່ອສະແດງ"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"ຫ້າມລົບກວນ"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d ເພີ່ມເຕີມ"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"ການແຈ້ງເຕືອນທີ່ສຳຄັນໜ້ອຍກວ່າຢູ່ດ້ານລຸ່ມ"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"ແຕະອີກຄັ້ງເພື່ອເປີດ"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"ເລື່ອນຂຶ້ນເພື່ອປົດລັອກ"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"ປັດຂວາເພື່ອໃຊ້ໂທລະສັບ"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"ປັດຊ້າຍເພື່ອໃຊ້ກ້ອງ"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"ຈົນກວ່າທ່ານຈະປິດ"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ກຳລັງສາກໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າຈະເຕັມ)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"ແຂກ"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ ແຂກ"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"ເປັນເວລານຶ່ງນາທີ"</item>
<item quantity="other" msgid="6924190729213550991">"ເປັນເວລາ %d ນາທີ"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"ເປັນເວລານຶ່ງຊົ່ວໂມງ"</item>
<item quantity="other" msgid="5408537517529822157">"ເປັນເວລາ %d ຊົ່ວໂມງ"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"ເປີດໃຊ້ໂຕປະຢັດແບັດເຕີຣີແລ້ວ"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"ປະສິດທິພາບຂອງອຸປະກອນຖືກຫຼຸດລົງແລ້ວ."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"ເປີດການຕັ້ງຄ່າໂຕປະຢັດແບັດເຕີຣີ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 574e559..cc1ac06 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nėra įspėjimų"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Vykstantys"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Įspėjimai"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Prijunkite įkroviklį"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Akumuliatorius senka."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Akumuliatorius senka"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Liko <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Liko <xliff:g id="NUMBER">%d%%</xliff:g>. Akumuliatoriaus tausojimo priemonė įjungta."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB krovimas nepalaikomas.\nNaudokite tik pateiktą įkroviklį."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Akumuliatoriaus naudojimas"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB įkrovimas nepalaikomas."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Naudokite tik pateiktą kroviklį."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Nustatymai"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Paleisti akumuliatoriaus tausojimo priemonę?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Paleisti"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Paleisti akumuliatoriaus tausojimo priemonę"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Kad padėtų pailginti akumuliatoriaus naudojimo trukmę, akumuliatoriaus tausojimo priemonė sumažins įrenginio našumą.\n\nAkumuliatoriaus tausojimo priemonė bus išjungta, kai įrenginys bus prijungtas prie maitinimo šaltinio."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nustatymai"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lėktuvo režimas"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Įjungta."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Išjungta."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Prijungta."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Prisijungiama."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"„Bluetooth“ (<xliff:g id="NUMBER">%d</xliff:g> įreng.)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"„Bluetooth“ išjungta"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Šviesumas"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automatiškai sukti"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Sukimas užrakintas"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Užrakinta stačia padėtis"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Užrakinta gulsčia padėtis"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatinis kaitaliojimas"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Kaitaliojimas užrakintas"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Stačias"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Gulsčias"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Įvesties metodas"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Vietovė"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Vietovė išjungta"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Neprisijungta"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Perduoti ekraną"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Perduoti ekraną"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Šviesumas"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATINIS"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Pakeisti spalvas"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Nėra naujausių programų"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Programos informacija"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Įkrautas"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Kraunamas"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> iki visiško įkrovimo"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Neįkraunamas"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tinklas gali\nbūti stebimas"</string>
<string name="description_target_search" msgid="3091587249776033139">"Paieška"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Slyskite aukštyn link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Palieskite, kad būtų rodoma"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Netrukdyti"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Dar %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Mažiau skubūs pranešimai toliau"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Palieskite dar kartą, kad atidarytumėte"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Perbraukite aukštyn, kad atrakintumėte"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Perbraukite į dešinę, kad galėtumėte skambinti"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Perbraukite į kairę, kad būtų įjungtas fotoaparatas"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Kol išjungsite"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Svečias"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Svečias"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"1 min."</item>
<item quantity="other" msgid="6924190729213550991">"%d min."</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"1 val."</item>
<item quantity="other" msgid="5408537517529822157">"%d val."</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Akumuliatoriaus tausojimo priemonė įjungta"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Įrenginio našumas sumažintas."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Atidaryti akumuliatoriaus tausojimo priemonės nustatymus"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 398553d..4e3a676 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nav paziņojumu"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Notiekošs"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Paziņojumi"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Pievienojiet uzlādes ierīci."</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Akumulators drīz izlādēsies."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Zems akumulatora enerģijas līmenis"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Atlicis: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Atlikuši <xliff:g id="NUMBER">%d%%</xliff:g>. Ir ieslēgts akumulatora enerģijas taupīšanas režīms."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB lādēšana netiek atbalstīta.\nIzmantojiet tikai komplektā iekļauto lādētāju."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Akumulatora lietojums"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB uzlāde netiek atbalstīta."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Izmantojiet tikai komplektā iekļauto lādētāju."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Iestatījumi"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Vai ieslēgt akumulatora enerģijas taupīšanas režīmu?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Ieslēgt"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Ieslēgt akumulatora enerģijas taupīšanas režīmu"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Lai paildzinātu akumulatora darbības laiku, akumulatora enerģijas taupīšanas režīmā tiks pazemināta ierīces veiktspēja.\n\nAkumulatora enerģijas taupīšanas režīms tiks atspējots, kad ierīce tiks pievienota uzlādes avotam."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Iestatījumi"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lidmašīnas režīms"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Ieslēgts"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Izslēgts"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Savienojums ir izveidots."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Notiek savienojuma izveide..."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> ierīce(-es))"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth savienojums ir izslēgts."</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Spilgtums"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automātiska pagriešana"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Pagriešana bloķēta"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Fiksēts portreta režīmā"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Fiksēts ainavas režīmā"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automātiska pagriešana"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Pagriešana bloķēta"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Portrets"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Ainava"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Ievades metode"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Atrašanās vieta"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Atrašanās vieta izslēgta"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nav izveidots savienojums"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Apraides ekrāns"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Apraides ekrāns"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Spilgtums"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMĀTISKI"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invertēt krāsas"</string>
@@ -213,10 +218,13 @@
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Piesaiste"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Tīklājs"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Paziņojumi"</string>
- <!-- no translation found for recents_empty_message (7883614615463619450) -->
- <skip />
+ <string name="recents_empty_message" msgid="7883614615463619450">"Nav nesen izmantotu lietotņu"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informācija par lietojumprogrammu"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulators uzlādēts"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Notiek uzlāde"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> līdz pilnam akumulatoram"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nenotiek uzlāde"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tīkls var\ntikt uzraudzīts"</string>
<string name="description_target_search" msgid="3091587249776033139">"Meklēt"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Velciet uz augšu, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -227,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Pieskarieties, lai rādītu"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Netraucēt"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"vēl %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Mazāk steidzami paziņojumi tiek rādīti tālāk"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Pieskarieties vēlreiz, lai atvērtu"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Velciet uz augšu, lai atbloķētu"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Lai lietotu tālruni, velciet pa labi."</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Lai lietotu kameru, velciet pa kreisi."</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Līdz brīdim, kad izslēgsiet"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Notiek uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Viesis"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+Viesis"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Vienu minūti"</item>
<item quantity="other" msgid="6924190729213550991">"%d min"</item>
@@ -242,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Vienu stundu"</item>
<item quantity="other" msgid="5408537517529822157">"%d h"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Ieslēgts akumulatora enerģijas taupīšanas režīms"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Ierīces veiktspēja ir pazemināta."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Atvērt akumulatora enerģijas taupīšanas režīma iestatījumus"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 6a2e79e..a2568d1 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Мэдэгдэл байхгүй"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Гарсан"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Мэдэгдэл"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Цэнэглэгчийг холбоно уу"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Батерей дуусаж байна."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Батерей дуусаж байна"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> үлдсэн"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> үлдсэн. Батерей хэмнэгч асаалттай."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB цэнэглэлт дэмжигдэхгүй байна.\nЗөвхөн нийлүүлэгдсэн цэнэглэгчийг ашиглана уу."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Батерей ашиглах"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB-р цэнэглэх дэмжигддэггүй."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Зөвхөн зориулалтын ирсэн цэнэглэгч ашиглана уу."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Тохиргоо"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Батерей хэмнэгчийг эхлүүлэх үү?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Эхлэх"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Батерей хэмнэгчийг эхлүүлэх"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Батарейны ашиглалтыг уртасгахын тулд Батарей хэмнэгч нь таны төхөөрөмжийн ажиллагааг бууруулах болно.\n\nБатарей хэмнэгч нь та төхөөрөмжөө цэнэглэх үед унтарна."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Тохиргоо"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Нислэгийн горим"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Идэвхижсэн."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Унтраах"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Холбогдсон."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Холбож байна."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Блютүүт (<xliff:g id="NUMBER">%d</xliff:g> төхөөрөмж)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Блютүүт унтраалттай"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Тодрол"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Автомат эргэх"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Эргүүлэлт түгжигдсэн"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Босоо байдлаар түгжсэн"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Хэвтээ байдлаар түгжсэн"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Автоматаар эргэх"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Эргэлтийг түгжсэн"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Босоо"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Хэвтээ"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Оруулах арга"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Байршил"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Байршил идэвхгүй"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Холбогдоогүй"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Дамжуулах дэлгэц"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Дамжуулах дэлгэц"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Тодрол"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОМАТ"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Өнгийг урвуулах"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Сүүлд ашигласан апп байхгүй"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Аппликешны мэдээлэл"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"хайх"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Цэнэглэгдсэн"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Цэнэглэж байна"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"дүүргэхэд <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Цэнэглэхгүй байна"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Сүлжээ хянагдаж\nбайж болзошгүй"</string>
<string name="description_target_search" msgid="3091587249776033139">"Хайх"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-г гулсуулах."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Харуулах бол хүрнэ үү"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Бүү саад бол"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"өөр %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Яаралтай биш мэдэгдлүүдийг доор"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Нээхийн тулд дахин товшино уу"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Түгжээг тайлах бол шудрана уу"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Утас гаргахын тулд баруун шударна уу"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Камер гаргахын тулд зүүн шударна уу"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Таныг унтраах хүртэл"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Зочин"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Зочин"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Нэг минутын турш"</item>
<item quantity="other" msgid="6924190729213550991">"%d минутын турш"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Нэг цагийн турш"</item>
<item quantity="other" msgid="5408537517529822157">"%d цагийн турш"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Батерей хэмнэгч асаалттай"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Төхөөрөмжийн ажиллагааг бууруулсан."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Батерей хэмнэгчийн тохиргоог нээх"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 7ae9b55..7d8a1ad 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Tiada pemberitahuan"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sedang berlangsung"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Pemberitahuan"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Sambungkan pengecas"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Bateri semakin lemah."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Bateri rendah"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Berbaki <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> yang tinggal. Penjimat bateri dihidupkan."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Pengecasan USB tidak disokong.\nGunakan hanya pengecas yang dibekalkan."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Penggunaan bateri"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Pengecasan USB tidak disokong."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Gunakan pengecas yang dibekalkan sahaja."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Tetapan"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Hidupkan penjimat bateri?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Bermula"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Hidupkan penjimat bateri"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Untuk membantu meningkatkan hayat bateri, penjimat Bateri akan mengurangkan prestasi peranti anda.\n\nPenjimat bateri akan dilumpuhkan apabila peranti anda disambungkan kepada sumber kuasa."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Tetapan"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mod pesawat"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Dihidupkan."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Dimatikan."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Disambungkan."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Menyambung."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Peranti)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Dimatikan"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Kecerahan"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Auto Putar"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Putaran Dikunci"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Dikunci kepada Potret"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Dikunci kepada Landskap"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Autoputar"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Putaran dikunci"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Potret"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Landskap"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Kaedah Input"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Lokasi"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Lokasi Dimatikan"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Tidak Disambungkan"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Skrin Cast"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Skrin Cast"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Terbalikkan warna"</string>
@@ -213,10 +218,13 @@
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Penambatan"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Tempat liputan"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Pemberitahuan"</string>
- <!-- no translation found for recents_empty_message (7883614615463619450) -->
- <skip />
+ <string name="recents_empty_message" msgid="7883614615463619450">"Tiada apl terbaharu"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Maklumat Aplikasi"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Sudah dicas"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Mengecas"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Lagi <xliff:g id="CHARGING_TIME">%s</xliff:g> untuk penuh"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Tidak mengecas"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rangkaian mungkin\nboleh dipantau"</string>
<string name="description_target_search" msgid="3091587249776033139">"Carian"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Luncurkan ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -227,13 +235,18 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Sentuh untuk menunjukkan"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Jangan ganggu"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d lagi"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Pemberitahuan kurang penting di bawah"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Ketik lagi untuk membuka"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Leret ke atas untuk membuka kunci"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Leret ke kanan untuk telefon"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Leret ke kiri untuk kamera"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Sehingga anda matikan"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengecas (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
+ <!-- no translation found for guest_nickname (8059989128963789678) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (4259024453643879653) -->
+ <skip />
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Selama satu minit"</item>
<item quantity="other" msgid="6924190729213550991">"Selama %d minit"</item>
@@ -242,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Selama satu jam"</item>
<item quantity="other" msgid="5408537517529822157">"Selama %d jam"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Penjimat bateri dihidupkan"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Prestasi peranti dikurangkan."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Buka tetapan penjimat bateri"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index e842c0f..cecbe7a 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen varslinger"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktiviteter"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Varslinger"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Koble til lader"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Lavt batterinivå."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Batterikapasiteten er lav"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> gjenværende"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> gjenstår. Batterisparing er på."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB-lading støttes ikke.\nBruk kun den medfølgende laderen."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Batteribruk"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Lading via USB støttes ikke."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Bruk bare den tilhørende laderen."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Innstillinger"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Vil du starte batterisparing?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Start"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Start batterisparing"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"For å spare batteritid reduserer Batterisparing enhetens ytelse.\n\nBatterisparing deaktiveres når enheten er koblet til en lader."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Innstillinger"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Trådløse nettverk"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flymodus"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"På."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Av."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Tilkoblet."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Kobler til."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheter)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth er slått av"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Lysstyrke"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automatisk rotasjon"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotasjon er låst"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Låst til stående format"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Låst til liggende format"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Rotér automatisk"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotasjonen er låst"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Portrett"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Landskap"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Inndatametode"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Sted"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Posisjon av"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ikke tilkoblet"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Cast skjermen"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Cast skjermen"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverter farger"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Ingen nylige apper"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformasjon"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Oppladet"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Lader"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Fulladet om <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Lader ikke"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nettverket kan\nvære overvåket"</string>
<string name="description_target_search" msgid="3091587249776033139">"Søk"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Dra opp for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Trykk for å vise"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Ikke forstyrr"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d til"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre presserende varsler nedenfor"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Trykk på nytt for å åpne"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Sveip oppover for å låse opp"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Sveip mot høyre for å åpne telefonen"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Sveip mot venstre for å åpne kameraet"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Inntil du slår av funksjonen"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Lader (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Gjest"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Gjest"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"I ett minutt"</item>
<item quantity="other" msgid="6924190729213550991">"I %d minutter"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"I én time"</item>
<item quantity="other" msgid="5408537517529822157">"I %d timer"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparing er på"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Enhetsytelsen er redusert."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Åpen innstilling for batterisparing"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 360b71d..b6ffecf 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Geen meldingen"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Actief"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meldingen"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Sluit de oplader aan"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"De accu raakt leeg."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Accu is bijna leeg"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> resterend"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> resterend. Accubesparing is ingeschakeld."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Opladen via USB niet ondersteund.\nGebruik alleen de bijgeleverde oplader."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Accugebruik"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Opladen via USB wordt niet ondersteund."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Gebruik alleen de bijgeleverde oplader."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Instellingen"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Accubesparing starten?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Starten"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Accubesparing starten"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Om de gebruiksduur van de accu te verbeteren, beperkt Accubesparing de prestaties van uw apparaat.\n\nAccubesparing wordt uitgeschakeld wanneer uw apparaat wordt aangesloten op een stopcontact."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Instellingen"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wifi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Vliegmodus"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Ingeschakeld."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Uitgeschakeld."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Verbonden."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Verbinden."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> apparaten)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth uit"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Helderheid"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automatische rotatie"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotatie vergrendeld"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Vergrendeld in staande stand"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Vergrendeld in liggende stand"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatische rotatie"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotatie vergrendeld"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Portret"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Landschap"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Invoermethode"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Locatie"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Locatie uit"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Niet verbonden"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Scherm casten"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Scherm casten"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATISCH"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Kleuren omkeren"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Geen recente apps"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"App-informatie"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opgeladen"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Opladen"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tot volledig opgeladen"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Wordt niet opgeladen"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk kan\nworden gecontroleerd"</string>
<string name="description_target_search" msgid="3091587249776033139">"Zoeken"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Veeg omhoog voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Raak aan om weer te geven"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Niet storen"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Nog %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Minder urgente meldingen onderaan"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Tik nogmaals om te openen"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Veeg omhoog om te ontgrendelen"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Veeg naar rechts voor telefoon"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Veeg naar links voor camera"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Totdat u dit uitschakelt"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Gast"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Gast"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Eén minuut"</item>
<item quantity="other" msgid="6924190729213550991">"%d minuten"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Eén uur"</item>
<item quantity="other" msgid="5408537517529822157">"%d uur"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Accubesparing is ingeschakeld"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"De prestaties van het apparaat worden beperkt."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Instellingen voor Accubesparing openen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 25098d8..05dcd82 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Brak powiadomień"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Bieżące"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Powiadomienia"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Podłącz ładowarkę"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Bateria wkrótce się rozładuje."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Bateria jest słaba"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Pozostało: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Zostało <xliff:g id="NUMBER">%d%%</xliff:g>. Oszczędzanie baterii jest włączone."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Ładowanie przy użyciu złącza USB nie jest obsługiwane.\nNależy używać tylko dołączonej ładowarki."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Użycie baterii"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Ładowanie przez USB nie jest obsługiwane."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Używaj tylko ładowarki dostarczonej z urządzeniem."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Ustawienia"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Włączyć oszczędzanie baterii?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Włącz"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Włącz oszczędzanie baterii"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Funkcja oszczędzania baterii zmniejszy szybkość działania urządzenia, by ograniczyć wykorzystanie energii.\n\nOszczędzanie baterii wyłączy się, kiedy urządzenie będzie podłączone do źródła zasilania."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ustawienia"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Tryb samolotowy"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Wł."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Wył."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Połączono."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Łączę..."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (urządzenia: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth wył."</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Jasność"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Autoobracanie"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Obracanie jest zablokowane"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Zablokowano w orientacji pionowej"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Zablokowano w orientacji poziomej"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Autoobracanie"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Obracanie zablokowane"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Pionowo"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Poziomo"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Metoda wprowadzania"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Lokalizacja"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Lokalizacja wyłączona"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Brak połączenia"</string>
<string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Brak sieci"</string>
<string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wyłącz Wi-Fi"</string>
- <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Ekran Cast"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Ekran Cast"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jasność"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATYCZNA"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Odwróć kolory"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Brak ostatnio uruchomionych aplikacji"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacje o aplikacji"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"szukaj"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Naładowana"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Ładuje się"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do pełnego naładowania"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nie ładuje"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieć może być\nmonitorowana"</string>
<string name="description_target_search" msgid="3091587249776033139">"Szukaj"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Przesuń w górę: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Dotknij, by zobaczyć"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Nie przeszkadzać"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d więcej"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Poniżej widać mniej pilne powiadomienia"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Kliknij ponownie, by otworzyć"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Przesuń w górę, by odblokować"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Przesuń w prawo, by przełączyć się na telefon"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Przesuń w lewo, by przełączyć się na aparat"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Dopóki nie wyłączysz"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ładuje się (pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Gość"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Dodaj gościa"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Przez minutę"</item>
<item quantity="other" msgid="6924190729213550991">"Przez %d min"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Przez godzinę"</item>
<item quantity="other" msgid="5408537517529822157">"Przez %d godz."</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Oszczędzanie baterii jest włączone"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Urządzenie działa z ograniczoną szybkością."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otwórz ustawienia oszczędzania baterii"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 34adc46..657e03f 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em curso"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Ligar carregador"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"A bateria está a ficar fraca."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Bateria fraca"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> restantes. A Poupança de bateria está ligada."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Carregamento USB não suportado. \nUtilize apenas o carregador fornecido."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Utilização da bateria"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"O carregamento por USB não é suportado."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Utilize apenas o carregador fornecido."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Definições"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Iniciar a poupança de bateria?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Iniciar"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Iniciar a poupança de bateria"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Para ajudar a aumentar a duração da bateria, a Poupança de bateria reduzirá o desempenho do seu dispositivo.\n\nA Poupança de bateria será desativada assim que o dispositivo for ligado à corrente elétrica."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Definições"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo de avião"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Ativado."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Desativado."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Ligado."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"A ligar..."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Dispositivos)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desat."</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Brilho"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Rodar automat."</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotação Bloqueada"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Bloqueado em retrato"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Bloqueado em paisagem"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Rotação automática"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotação bloqueada"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Retrato"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Paisagem"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Método de Introdução"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Localização"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Localização Desativada"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Não Ligado"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Transmitir ecrã"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Transmitir ecrã"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverter cores"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Nenhuma aplicação recente"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações da aplicação"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"A carregar"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> até ficar completa"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Não está a carregar"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode ser\nmonitorizada"</string>
<string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Deslize para cima para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toque para mostrar"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Não incomodar"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Mais %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Notificações menos urgentes abaixo"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Toque novamente para abrir"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Deslizar rapidamente com o dedo para cima para desbloquear"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Deslize rapidamente para a direita para aceder ao telemóvel"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Deslize rapidamente para a esquerda para aceder à câmara"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Até que o utilizador desative"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"A carregar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Convidado"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Convidado"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Durante um minuto"</item>
<item quantity="other" msgid="6924190729213550991">"Durante %d minutos"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Durante uma hora"</item>
<item quantity="other" msgid="5408537517529822157">"Durante %d horas"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"A poupança de bateria está ligada"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"O desempenho do dispositivo é reduzido."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir as definições de poupança de bateria"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index e3b1f846..bcf7431 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em andamento"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Conecte o carregador"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"A bateria está ficando baixa."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Bateria fraca"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> restante(s). A Economia de bateria está ativada."</string>
<string name="invalid_charger" msgid="4549105996740522523">"O carregamento via USB não é suportado.\nUse apenas o carregador fornecido."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Uso da bateria"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"O carregamento via USB não é suportado."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Use apenas o carregador fornecido."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Configurações"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Iniciar a economia de bateria?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Iniciar"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Iniciar economia de bateria"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Para ajudar a melhorar a vida útil da bateria, a Economia de bateria reduzirá o desempenho do dispositivo.\n\nA Economia de bateria será desativada quando o dispositivo estiver carregando."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configurações"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo avião"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Ligado."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Desligado."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Conectado."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Conectando."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth desativado"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Brilho"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Girar automat."</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotação bloqueada"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Bloqueado no modo retrato"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Bloqueado no modo paisagem"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Rotação automática"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotação bloqueada"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Retrato"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Paisagem"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Método de entrada"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Localização"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Localização desativada"</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Não conectado"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Transmitir tela"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Transmitir tela"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inverter cores"</string>
@@ -215,10 +220,13 @@
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Ponto de acesso"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Notificações"</string>
- <!-- no translation found for recents_empty_message (7883614615463619450) -->
- <skip />
+ <string name="recents_empty_message" msgid="7883614615463619450">"Nenhum app recente"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do aplicativo"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Carregando"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> até concluir"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Não está carregando"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode estar\nsob monitoração"</string>
<string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para cima."</string>
@@ -229,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toque para mostrar"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Não perturbe"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Mais %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Notificações menos urgentes abaixo"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Toque novamente para abrir"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Deslize para cima para desbloquear"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Deslize para a esquerda para usar o telefone"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Deslize para a esquerda para usar a câmera"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Até você desativar"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Convidado"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ convidado"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Por 1 minuto"</item>
<item quantity="other" msgid="6924190729213550991">"Por %d minutos"</item>
@@ -244,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Por 1 hora"</item>
<item quantity="other" msgid="5408537517529822157">"Por %d horas"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"A Economia de bateria está ativada"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"O desempenho do dispositivo foi reduzido."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Abrir configurações de economia de bateria"</string>
</resources>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index e6a3872..689aaff 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -35,15 +35,28 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nagins avis"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Actual"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Avis"</string>
- <!-- no translation found for battery_low_title (2783104807551211639) -->
- <skip />
- <!-- no translation found for battery_low_subtitle (1752040062087829196) -->
+ <!-- no translation found for battery_low_title (6456385927409742437) -->
<skip />
<!-- no translation found for battery_low_percent_format (1077244949318261761) -->
<skip />
+ <!-- no translation found for battery_low_percent_format_saver_started (6534746636002666456) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
- <string name="battery_low_why" msgid="7279169609518386372">"Consum dad accu"</string>
+ <!-- no translation found for invalid_charger_title (3515740382572798460) -->
+ <skip />
+ <!-- no translation found for invalid_charger_text (5474997287953892710) -->
+ <skip />
+ <!-- no translation found for battery_low_why (4553600287639198111) -->
+ <skip />
+ <!-- no translation found for battery_saver_confirmation_title (5987726159603849352) -->
+ <skip />
+ <!-- no translation found for battery_saver_confirmation_ok (7283108887345688413) -->
+ <skip />
+ <!-- no translation found for battery_saver_start_action (7245333922937402896) -->
+ <skip />
+ <!-- no translation found for battery_saver_confirmation_text (8417584516834617662) -->
+ <skip />
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
<!-- no translation found for status_bar_settings_wifi_button (1733928151698311923) -->
@@ -342,13 +355,13 @@
<skip />
<!-- no translation found for quick_settings_brightness_label (6968372297018755815) -->
<skip />
- <!-- no translation found for quick_settings_rotation_unlocked_label (336054930362580584) -->
+ <!-- no translation found for quick_settings_rotation_unlocked_label (7305323031808150099) -->
<skip />
- <!-- no translation found for quick_settings_rotation_locked_label (8058646447242565486) -->
+ <!-- no translation found for quick_settings_rotation_locked_label (6359205706154282377) -->
<skip />
- <!-- no translation found for quick_settings_rotation_locked_portrait_label (1553131290066230775) -->
+ <!-- no translation found for quick_settings_rotation_locked_portrait_label (5102691921442135053) -->
<skip />
- <!-- no translation found for quick_settings_rotation_locked_landscape_label (7216265671276086593) -->
+ <!-- no translation found for quick_settings_rotation_locked_landscape_label (8553157770061178719) -->
<skip />
<!-- no translation found for quick_settings_ime_label (7073463064369468429) -->
<skip />
@@ -376,7 +389,7 @@
<skip />
<!-- no translation found for quick_settings_wifi_off_label (7558778100843885864) -->
<skip />
- <!-- no translation found for quick_settings_remote_display_no_connection_label (372107699274391290) -->
+ <!-- no translation found for quick_settings_remote_display_no_connection_label (7482103121002965053) -->
<skip />
<!-- no translation found for quick_settings_brightness_dialog_title (8599674057673605368) -->
<skip />
@@ -400,6 +413,14 @@
<skip />
<!-- no translation found for recents_search_bar_label (8074997400187836677) -->
<skip />
+ <!-- no translation found for expanded_header_battery_charged (5945855970267657951) -->
+ <skip />
+ <!-- no translation found for expanded_header_battery_charging (205623198487189724) -->
+ <skip />
+ <!-- no translation found for expanded_header_battery_charging_with_time (457559884275395376) -->
+ <skip />
+ <!-- no translation found for expanded_header_battery_not_charging (4798147152367049732) -->
+ <skip />
<!-- no translation found for ssl_ca_cert_warning (9005954106902053641) -->
<skip />
<!-- no translation found for description_target_search (3091587249776033139) -->
@@ -414,17 +435,34 @@
<skip />
<!-- no translation found for zen_mode_title (8793432092004749188) -->
<skip />
- <!-- no translation found for keyguard_more_overflow_text:other (9180696159506883684) -->
+ <!-- no translation found for keyguard_more_overflow_text (9195222469041601365) -->
+ <skip />
<!-- no translation found for speed_bump_explanation (1288875699658819755) -->
<skip />
<!-- no translation found for notification_tap_again (7590196980943943842) -->
<skip />
<!-- no translation found for keyguard_unlock (8043466894212841998) -->
<skip />
+ <!-- no translation found for phone_hint (3101468054914424646) -->
+ <skip />
+ <!-- no translation found for camera_hint (5241441720959174226) -->
+ <skip />
<!-- no translation found for zen_mode_forever (7420011936770086993) -->
<skip />
+ <!-- no translation found for keyguard_indication_charging_time (1757251776872835768) -->
+ <skip />
+ <!-- no translation found for guest_nickname (8059989128963789678) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (4259024453643879653) -->
+ <skip />
<!-- no translation found for zen_mode_duration_minutes:one (9040808414992812341) -->
<!-- no translation found for zen_mode_duration_minutes:other (6924190729213550991) -->
<!-- no translation found for zen_mode_duration_hours:one (3480040795582254384) -->
<!-- no translation found for zen_mode_duration_hours:other (5408537517529822157) -->
+ <!-- no translation found for battery_saver_notification_title (237918726750955859) -->
+ <skip />
+ <!-- no translation found for battery_saver_notification_text (7796554871101546872) -->
+ <skip />
+ <!-- no translation found for battery_saver_notification_action_text (7546297220816993504) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 9bc9178..c099dd9 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nicio notificare"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"În desfăşurare"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificări"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Conectaţi încărcătorul"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Bateria este descărcată."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Bateria este aproape descărcată"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Rămas: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Procent rămas din baterie: <xliff:g id="NUMBER">%d%%</xliff:g>. Economisirea bateriei este activată."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Încărcarea USB nu este acceptată. \nUtilizaţi numai încărcătorul furnizat."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Utilizarea bateriei"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Încărcarea prin USB nu este acceptată."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Utilizați numai încărcătorul furnizat."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Setări"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Porniți economisirea bateriei?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Începeți"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Porniți economisirea bateriei"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Pentru a mări autonomia bateriei, funcția Economisirea bateriei reduce performanța dispozitivului.\n\nEconomisirea bateriei se dezactivează când dispozitivul este conectat la priză."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Setări"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mod Avion"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Activat."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Dezactivat."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Conectat."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Se conectează."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispozitive)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth dezactivat"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Luminozitate"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Rotire automată"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotire blocată"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Blocat la afișarea „portret”"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Blocat la afișarea „peisaj”"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Rotire automată"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotire blocată"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Portret"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Peisaj"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Metodă de introducere"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Locație"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Localizarea este dezactivată"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Neconectat"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Ecran de afișare a transmisiunii"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Ecran de trimitere"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminozitate"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAT"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Inversați culori"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Nicio aplicație recentă"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"S-a încărcat"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Se încarcă"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> până la încărcare completă"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nu se încarcă"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rețeaua poate\nfi monitorizată"</string>
<string name="description_target_search" msgid="3091587249776033139">"Căutaţi"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Glisaţi în sus pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,18 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Atingeți pentru a afișa"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Nu deranjaţi"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Încă %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Notificările mai puțin urgente mai jos"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Atingeți din nou pentru a deschide"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Glisați în sus pentru a debloca"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Glisați la dreapta pentru a acesa telefonul"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Glisați la stânga pentru a accesa camera foto"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Până la dezactivare"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Se încarcă (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
+ <!-- no translation found for guest_nickname (8059989128963789678) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (4259024453643879653) -->
+ <skip />
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Timp de un minut"</item>
<item quantity="other" msgid="6924190729213550991">"Timp de %d (de) minute"</item>
@@ -241,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Timp de o oră"</item>
<item quantity="other" msgid="5408537517529822157">"Timp de %d (de) ore"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Economisirea bateriei este activată"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Performanța dispozitivului s-a redus."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Deschideți setările pentru economisirea bateriei"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 619ebc2..8c59e05 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Нет уведомлений"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Текущие"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Уведомления"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Подключите зарядное устройство"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Батарея разряжена."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Батарея почти разряжена"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Осталось <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Уровень заряда батареи: <xliff:g id="NUMBER">%d%%</xliff:g>. Включен режим энергосбережения."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Зарядка через порт USB не поддерживается.\nИспользуйте только зарядное устройство из комплекта поставки."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Подробнее"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Зарядка через USB не поддерживается."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Используйте только зарядное устройство, поставляемое в комплекте с устройством."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Настройки"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Включить режим энергосбережения?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"ОК"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Включить режим энергосбережения"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Для экономии заряда батареи производительность устройства будет снижена.\n\nКогда устройство заряжается, режим энергосбережения отключен."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим полета"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Вкл."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Выкл."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Подключено"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Соединение."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth выкл."</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Яркость"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Автоповорот"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Автоповорот выкл."</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Только вертикально"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Только горизонтально"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Автоповорот"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Автоповорот отключен"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Вертикальная ориентация"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Горизонтальная ориентация"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Способ ввода"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Передача геоданных"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Местоположение выкл."</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Нет соединения"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Wi-Fi-монитор"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Беспроводной монитор"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркость"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОНАСТРОЙКА"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Инвертировать"</string>
@@ -218,6 +223,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Ничего не найдено."</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Сведения о приложении"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"поиск"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Батарея заряжена"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Зарядка батареи"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> до полной зарядки"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Не заряжается"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Действия в сети\nмогут отслеживаться"</string>
<string name="description_target_search" msgid="3091587249776033139">"Поиск"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Проведите вверх, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -228,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Нажмите, чтобы открыть"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Не беспокоить"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Ещё %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Показать менее важные оповещения"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Нажмите ещё раз, чтобы открыть"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Для разблокировки проведите пальцем по экрану"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Чтобы открыть приложение \"Телефон\", пролистните вправо"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Чтобы включить камеру, пролистните влево"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Пока я не отключу"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядка батареи (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Гость"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Добавить гостя"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"1 мин."</item>
<item quantity="other" msgid="6924190729213550991">"%d мин."</item>
@@ -243,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"1 ч."</item>
<item quantity="other" msgid="5408537517529822157">"%d ч."</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Включен режим энергосбережения"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Производительность устройства снижена."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Открыть настройки режима энергосбережения"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index df880cf..9456ebd 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Žiadne upozornenia"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Prebiehajúce"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Upozornenia"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Pripojte nabíjačku"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Batéria je skoro vybitá."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Batéria je takmer vybitá"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Zostáva: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Zostáva: <xliff:g id="NUMBER">%d%%</xliff:g>. Šetrič batérie je zapnutý."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Nabíjanie pomocou rozhrania USB nie je podporované.\nPoužívajte iba nabíjačku, ktorá bola dodaná spolu so zariadením."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Využitie batérie"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Nabíjanie prostredníctvom USB nie je podporované."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Používajte iba originálnu nabíjačku."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Nastavenia"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Chcete spustiť šetrič batérie?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Spustiť"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Spustiť šetrič batérie"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Šetrič batérie zníži výkonnosť vášho zariadenia, aby tak predĺžil výdrž batérie.\n\nPo pripojení zariadenia do zásuvky sa šetrič batérie deaktivuje."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavenia"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Režim V lietadle"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Zapnuté."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Vypnuté."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Pripojené."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Pripája sa"</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Rozhranie Bluetooth (počet zariadení: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Rozhranie Bluetooth je vypnuté"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Jas"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Automatické otáčanie"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Otáčanie uzamknuté"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Uzamknuté na výšku"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Uzamknuté na šírku"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatické otáčanie"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Otáčanie je uzamknuté"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Na výšku"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Na šírku"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Metóda vstupu"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Poloha"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Poloha vypnutá"</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nepripojené"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Vzdialená obrazovka"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Vzdialená obrazovka"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jas"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invertovať farby"</string>
@@ -218,6 +223,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Žiadne nedávne aplikácie"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informácie o aplikácii"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"hľadať"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nabitá"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nabíja sa"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Úplné nabitie o <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Nenabíja sa"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieť môže byť\nmonitorovaná"</string>
<string name="description_target_search" msgid="3091587249776033139">"Vyhľadávanie"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Prejdite prstom nahor: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -228,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Upozornenie zobrazíte dotykom"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Nerušiť"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d ďalších"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Menej naliehavé upozornenia sa nachádzajú nižšie"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Upozornenie otvoríte opätovným klepnutím"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Zariadenie odomknete prejdením prstom nahor"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Telefón otvoríte prejdením prstom doľava"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Fotoaparát otvoríte prejdením prstom doľava"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Dokým túto funkciu nevypnete"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíja sa (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Hosť"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Pridať hosťa"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Na jednu minútu"</item>
<item quantity="other" msgid="6924190729213550991">"Na %d min"</item>
@@ -243,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"Na jednu hodinu"</item>
<item quantity="other" msgid="5408537517529822157">"Na %d h"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Šetrič batérie je zapnutý"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Výkonnosť zariadenia sa znížila."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Otvorte nastavenia šetriča batérie"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index d1170bd..10ba09f 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ni obvestil"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Trenutno"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obvestila"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Priključite polnilnik"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Baterija je skoraj prazna."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Akumulator je skoraj izpraznjen"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> preostalo"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Še <xliff:g id="NUMBER">%d%%</xliff:g>. Varčevanje z energijo akumulatorja je vklopljeno."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Polnjenje po povezavi USB ni podprto.\nUporabite priloženi polnilnik."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Uporaba baterije"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Polnjenje prek USB-ja ni podprto."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Uporabljajte samo priloženi polnilnik."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Nastavitve"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Želite zagnati varčevanje z energijo akumulatorja?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Začni"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Zaženi varčevanje z energijo akumulatorja"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Zaradi podaljšanja delovanja akumulatorja funkcija Varčevanje z energijo akumulatorja zmanjša zmogljivost delovanja naprave.\n\nVarčevanje z energijo akumulatorja se onemogoči, ko je naprava priklopljena na zunanje napajanje."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavitve"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Način za letalo"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Vklopljen."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Izklopljen."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Povezan."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Povezovanje."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (št. naprav: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth izklopljen"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Svetlost"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Samodejno vrtenje"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Zaklenjeno vrtenje"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Zaklenjeno na pokončno postavitev"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Zaklenjeno na ležečo postavitev"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Samodejno sukanje"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Sukanje je zaklenjeno"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Pokončno"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Ležeče"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Način vnosa"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Lokacija"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Lokacija izklopljena"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Povezava ni vzpostavljena"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Zaslon za predvajanje"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Zaslon za predvajanje"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Svetlost"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"SAMODEJNO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Obrni barve"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Ni nedavnih aplikacij"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Podatki o aplikaciji"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulator napolnjen"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Polnjenje"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> do napolnjenosti"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Se ne polni"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Omrežje je\nlahko spremljano"</string>
<string name="description_target_search" msgid="3091587249776033139">"Iskanje"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Povlecite navzgor za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Dotaknite se za prikaz"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Ne moti"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"še %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Manj nujna obvestila spodaj"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Znova se dotaknite, da odprete"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Povlecite, da odklenete"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Povlecite v desno za telefon"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Povlecite v levo za fotoaparat"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Dokler tega ne izklopite"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Gost"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Dodajanje gosta"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Za eno minuto"</item>
<item quantity="other" msgid="6924190729213550991">"Za %d min"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Za eno uro"</item>
<item quantity="other" msgid="5408537517529822157">"Za %d h"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Varčevanje z energijo akumulatorja je vklopljeno"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Zmogljivost delovanja naprave je zmanjšana."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Odpri nastavitve varčevanja z energijo akumulatorja"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index cfb6a2c..3bee434 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Нема обавештења"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Текуће"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Обавештења"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Прикључите пуњач"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Батерија ће се ускоро испразнити."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Ниво напуњености батерије је низак"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"преостало је <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Преостало је још <xliff:g id="NUMBER">%d%%</xliff:g>. Штедња батерије је укључена."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Пуњење преко USB-а није подржано.\nКористите само приложени пуњач."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Коришћење батерије"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Пуњење преко USB-а није подржано."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Користите само пуњач који сте добили."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Подешавања"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Желите ли да покренете Штедњу батерије?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Покрени"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Покрените Штедњу батерије"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Да би продужила век трајања батерије, Штедња батерије ће умањити перформансе уређаја.\n\nШтедња батерије ће се искључити када укључите уређај."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Подешавања"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим рада у авиону"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Укључено."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Искључено."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Повезано је."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Повезивање."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> уређаја)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth искључен"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Осветљеност"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Аутоматско ротирање"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Ротирање је закључано"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Закључано на Усправно"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Закључано на Водоравно"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Аутоматска ротација"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Ротација је закључана"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Вертикални приказ"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Хоризонтални приказ"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Метод уноса"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Локација"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Локација је искључена"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Веза није успостављена"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Пребаци екран"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Пребацивање екрана"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Осветљеност"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АУТОМАТСКА"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Обрни боје"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Нема недавних апликација"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Информације о апликацији"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Напуњена је"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Пуњење"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> док се не напуни"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Не пуни се"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежа се можда\nнадгледа"</string>
<string name="description_target_search" msgid="3091587249776033139">"Претрага"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Превуците нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Додирните за приказ"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Не узнемиравај"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Још %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Мање хитна обавештења су у наставку"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Додирните поново да бисте отворили"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Превуците нагоре да бисте откључали"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Превуците удесно за телефон"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Превуците улево за камеру"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Док не искључите"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Пуњење (пун је за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Гост"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Гост"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Један минут"</item>
<item quantity="other" msgid="6924190729213550991">"%d мин"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Један сат"</item>
<item quantity="other" msgid="5408537517529822157">"%d с"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Штедња батерије је укључена"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Перформансе уређаја су умањене."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Отворите подешавања Штедње батерије"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 4e3d72f..b802a48 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Inga aviseringar"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Pågående"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelanden"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Anslut laddaren"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteriet håller på att ta slut."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Lågt batteri"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> återstår"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> kvar. Batterisparläget har aktiverats."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Det går inte att ladda via USB.\nAnvänd endast den laddare som levererades med telefonen."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Batteriförbrukning"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Det finns inget stöd för laddning via USB."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Använd endast den medföljande laddaren."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Inställningar"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Vill du aktivera batterisparläget?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Börja"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Aktivera batterisparläget"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Med batterisparläget minskas enhetens prestanda i syfte att förlänga batteritiden.\n\nBatterisparläget inaktiveras när enheten ansluts till ett uttag."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Inställningar"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flygplansläge"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Aktiverad."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Inaktiverad."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Ansluten."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Ansluter."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheter)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth av"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Ljusstyrka"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Rotera automatiskt"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Rotationen har låsts"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Låst i stående läge"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Låst i liggande läge"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Rotera automatiskt"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotationen har låsts"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Stående"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Liggande"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Inmatningsmetod"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Plats"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Plats har inaktiverats"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ej ansluten"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Överför skärmen"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Casta skärmen"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ljusstyrka"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Invertera färger"</string>
@@ -213,10 +218,13 @@
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Internetdelning"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Trådlös surfzon"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Aviseringar"</string>
- <!-- no translation found for recents_empty_message (7883614615463619450) -->
- <skip />
+ <string name="recents_empty_message" msgid="7883614615463619450">"Inga aktiva appar"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformation"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laddat"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Laddar"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> tills batteriet är fulladdat"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Laddar inte"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nätverket kan\nvara övervakat"</string>
<string name="description_target_search" msgid="3091587249776033139">"Sök"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Dra uppåt för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
@@ -227,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Tryck här om du vill visa aviseringar"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Stör ej"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d till"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre brådskande aviseringar nedan"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Tryck igen för att öppna"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Dra uppåt om du vill låsa upp"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Dra åt höger om du vill visa telefonen"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Dra åt vänster om du vill visa kameran"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Tills du inaktiverar detta"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laddar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tills batteriet är fulladdat)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Gäst"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Lägg till gäst"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"I en minut"</item>
<item quantity="other" msgid="6924190729213550991">"I %d minuter"</item>
@@ -242,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"I en timme"</item>
<item quantity="other" msgid="5408537517529822157">"I %d timmar"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparläget har aktiverats"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Enhetens prestanda har minskats."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Öppna inställningarna för batterisparläget"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 9bab46e..1cd1752 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -30,11 +30,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Hakuna arifa"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Inaendelea"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Arifa"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Unganisha chaja"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Betri inaisha."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Betri imeisha"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> zimebakia"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Imesalia <xliff:g id="NUMBER">%d%%</xliff:g>. Kiokoa betri kimewashwa."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Chaji ya USB haihamiliwi.\n Tumia chaka iliyopeanwa."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Utumiaji wa betri"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Kuchaji kwa kutumia USB hakutumiki."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Tumia chaja iliyonunuliwa pamoja na kifaa pekee."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Mipangilio"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Ungependa kuwasha kiokoa betri?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Anza"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Washa kiokoa betri"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Ili kusaidia kuboresha muda wa matumizi ya betri, Kiokoa betri kitapunguza utendaji wa kifaa chako.\n\nKiokoa betri kitazimwa kifaa chako kitakapochomekwa kwenye nishati ya umeme."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Mipangilio"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Mtandao-Hewa"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Hali ya Ndege"</string>
@@ -118,8 +124,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Imewashwa."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Imezimwa."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Imeunganishwa."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Inaunganisha."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -185,10 +190,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (Vifaa <xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Imezimwa"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Ung\'avu"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Zungusha Otomatiki"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Mzunguko Umefungwa"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Imefungwa katika mkamo Wima"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Imefungwa katika mkao Mlalo"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Zungusha kiotomatiki"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Mzunguko umefungwa"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Wima"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Mlalo"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Mbinu ya uingizaji"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Kutambua Eneo"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Kitambua eneo kimezimwa"</string>
@@ -202,7 +207,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Haijaunganishwa"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Utumaji wa Skrini"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Utumaji wa Skrini"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ung\'avu"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"KIOTOMATIKI"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Pindua rangi"</string>
@@ -214,6 +219,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Hakuna programu za karibuni"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Maelezo ya Programu"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Betri imejaa"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Inachaji"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> hadi ijae"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Haichaji"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Huenda mtandao\nunafuatiliwa"</string>
<string name="description_target_search" msgid="3091587249776033139">"Tafuta"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Sogeza juu kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
@@ -224,13 +233,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Gusa ili zionekane"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Usisumbue"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d zaidi"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>+"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Arifa zisizo za dharura sana ziko hapo chini"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Gonga tena ili ufungue"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Telezesha kidole ili ufungue"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Telezesha kidole kulia ili ufikie simu"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Telezesha kidole kushoto ili ufikie kamera"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Hadi utakapozima hili"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Inachaji ( <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hadi ijae)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Aliyealikwa"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Aliyealikwa"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Kwa dakika moja"</item>
<item quantity="other" msgid="6924190729213550991">"Kwa dakika %d"</item>
@@ -239,4 +251,7 @@
<item quantity="one" msgid="3480040795582254384">"Kwa saa moja"</item>
<item quantity="other" msgid="5408537517529822157">"Kwa saa %d"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Kiokoa betri kimewashwa"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Utendaji wa kifaa umepunguzwa."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Fungua mipangilio ya hali inayookoa betri"</string>
</resources>
diff --git a/core/res/res/layout/notification_quantum_media_action.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
similarity index 67%
copy from core/res/res/layout/notification_quantum_media_action.xml
copy to packages/SystemUI/res/values-sw600dp-land/config.xml
index 17f0848..f9b01c8 100644
--- a/core/res/res/layout/notification_quantum_media_action.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -14,12 +14,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-
-<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
- style="@android:style/Widget.Quantum.Light.Button.Borderless.Small"
- android:id="@+id/action0"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center"
- />
+<resources>
+ <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
+ card. -->
+ <integer name="keyguard_max_notification_count">3</integer>
+</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 326f602..5367fbc 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -23,5 +23,8 @@
<item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.25</item>
<fraction name="keyguard_clock_y_fraction_max">37%</fraction>
- <fraction name="keyguard_clock_y_fraction_min">14%</fraction>
+ <fraction name="keyguard_clock_y_fraction_min">20%</fraction>
+
+ <dimen name="keyguard_clock_notifications_margin_min">36dp</dimen>
+ <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 6dea81f..47581a9 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -28,4 +28,8 @@
<!-- The number of columns that the top level tiles span in the QuickSettings -->
<integer name="quick_settings_user_time_settings_tile_span">1</integer>
+
+ <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
+ card. -->
+ <integer name="keyguard_max_notification_count">5</integer>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 313e2e8..a5e3924 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -16,8 +16,8 @@
*/
-->
<resources>
- <!-- The width of the notification panel window: 446 + 16 + 16 (padding in the bg drawable) -->
- <dimen name="notification_panel_width">478dp</dimen>
+ <!-- The width of the notification panel window: 400 + 16 + 16 (padding in the bg drawable) -->
+ <dimen name="notification_panel_width">432dp</dimen>
<!-- Gravity for the notification panel -->
<!-- 0x31 = top|center_horizontal -->
@@ -56,10 +56,10 @@
max value is used when no notifications are displaying, and the min value is when the
highest possible number of notifications are showing. -->
<fraction name="keyguard_clock_y_fraction_max">34%</fraction>
- <fraction name="keyguard_clock_y_fraction_min">25%</fraction>
+ <fraction name="keyguard_clock_y_fraction_min">24%</fraction>
<!-- The margin between the clock and the notifications on Keyguard. See
keyguard_clock_height_fraction_* for the difference between min and max.-->
- <dimen name="keyguard_clock_notifications_margin_min">36dp</dimen>
- <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
+ <dimen name="keyguard_clock_notifications_margin_min">44dp</dimen>
+ <dimen name="keyguard_clock_notifications_margin_max">44dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 4820071..791d5f6 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"ไม่มีการแจ้งเตือน"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"ดำเนินอยู่"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"การแจ้งเตือน"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"เสียบที่ชาร์จ"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"แบตเตอรี่เหลือน้อย"</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"แบตเตอรี่เหลือน้อย"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"เหลืออีก <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"แบตเตอรี่เหลือ <xliff:g id="NUMBER">%d%%</xliff:g> เปิดโหมดประหยัดแบตเตอรี่อยู่"</string>
<string name="invalid_charger" msgid="4549105996740522523">"ไม่สนับสนุนการชาร์จแบบ USB\nใช้เฉพาะที่ชาร์จที่ให้มาเท่านั้น"</string>
- <string name="battery_low_why" msgid="7279169609518386372">"การใช้แบตเตอรี่"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"ไม่รองรับการชาร์จผ่าน USB"</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"ใช้เฉพาะที่ชาร์จที่ให้มา"</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"การตั้งค่า"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"เริ่มใช้โหมดประหยัดแบตเตอรี่ใช่ไหม"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"เริ่ม"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"เริ่มโหมดประหยัดแบตเตอรี่"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"เพื่อช่วยให้ใช้งานแบตเตอรี่ได้ยาวนานขึ้น โหมดประหยัดแบตเตอรี่จะลดประสิทธิภาพการทำงานของอุปกรณ์ลง\n\nโหมดประหยัดแบตเตอรี่จะปิดเมื่อคุณเสียบปลั๊กไฟกับอุปกรณ์"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"การตั้งค่า"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WiFi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"โหมดใช้งานบนเครื่องบิน"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"เปิดอยู่"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"ปิดอยู่"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"เชื่อมต่อแล้ว"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"กำลังเชื่อมต่อ"</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"บลูทูธ (<xliff:g id="NUMBER">%d</xliff:g> อุปกรณ์)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"ปิดบลูทูธ"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"ความสว่าง"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"หมุนอัตโนมัติ"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"ล็อกการหมุนแล้ว"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"ล็อกที่แนวตั้ง"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"ล็อกที่แนวนอน"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"หมุนอัตโนมัติ"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"ล็อกการหมุน"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"บุคคล"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"แนวนอน"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"วิธีป้อนข้อมูล"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"ตำแหน่ง"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"ปิดตำแหน่ง"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"ไม่ได้เชื่อมต่อ"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"ส่งหน้าจอ"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"ส่งหน้าจอ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ความสว่าง"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"อัตโนมัติ"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"สลับสี"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"ไม่มีแอปล่าสุด"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ข้อมูลแอปพลิเคชัน"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ค้นหา"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ชาร์จแล้ว"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"กำลังชาร์จ"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"อีก <xliff:g id="CHARGING_TIME">%s</xliff:g> จึงจะเต็ม"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"ไม่ได้ชาร์จ"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"เครือข่ายอาจ\nถูกตรวจสอบ"</string>
<string name="description_target_search" msgid="3091587249776033139">"ค้นหา"</string>
<string name="description_direction_up" msgid="7169032478259485180">"เลื่อนขึ้นเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"แตะเพื่อแสดง"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"ห้ามรบกวน"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"อีก %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"การแจ้งเตือนที่เร่งด่วนน้อยด้านล่าง"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"แตะอีกครั้งเพื่อเปิด"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"กวาดขึ้นเพื่อปลดล็อก"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"กวาดไปทางขวาเพื่อใช้โทรศัพท์"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"กวาดไปทางซ้ายเพื่อใช้กล้องถ่ายรูป"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"จนกว่าคุณจะปิดฟังก์ชันนี้"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"กำลังชาร์จ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> เต็ม)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"ผู้เข้าร่วม"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ ผู้เข้าร่วม"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"1 นาที"</item>
<item quantity="other" msgid="6924190729213550991">"%d นาที"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"1 ชั่วโมง"</item>
<item quantity="other" msgid="5408537517529822157">"%d ชั่วโมง"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"เปิดโหมดประหยัดแบตเตอรี่อยู่"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"ประสิทธิภาพการทำงานของอุปกรณ์ลดลง"</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"เปิดการตั้งค่าโหมดประหยัดแบตเตอรี่"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 6c6af51..42f262b 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Walang mga notification"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Nagpapatuloy"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Mga Notification"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Ikabit ang charger"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Humihina na ang baterya."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Mahina na ang baterya"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> natitira"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> ang natitira. Naka-on ang tagatipid ng baterya."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Hindi sinusuportahan ang pag-charge sa USB.\nGamitin lang ang ibinigay na charger."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Paggamit ng baterya"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Hindi sinusuportahan ang pagtsa-charge gamit ang USB."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Gamitin lang ang ibinigay na charger."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Mga Setting"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Simulan ang tagatipid ng baterya?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Magsimula"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Simulan ang tagatipid ng baterya"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Upang makatulong na patagalin ang baterya, babawasan ng Tagatipid ng baterya ang pagganap ng iyong device.\n\nIdi-disable ang tagatipid ng baterya kapag naka-plug in ang iyong device."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Mga Setting"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Airplane mode"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Naka-on."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Naka-off."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Nakakonekta."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Kumokonekta."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> (na) Device)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Naka-off ang Bluetooth"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Brightness"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"I-auto Rotate"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Naka-lock ang Pag-rotate"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Naka-lock sa Portrait"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Naka-lock sa Landscape"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Awtomatikong i-rotate"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Naka-lock ang pag-ikot"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Portrait"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Landscape"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Pamamaraan ng Pag-input"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Lokasyon"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Naka-off ang Lokasyon"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Hindi Nakakonekta"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"I-cast ang Screen"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"I-cast ang screen"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"I-invert ang mga kulay"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Walang kamakailang mga app"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Impormasyon ng Application"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"maghanap"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nasingil na"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Nagcha-charge"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> hanggang mapuno"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Hindi nagcha-charge"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Maaaring\nsinusubaybayan ang network"</string>
<string name="description_target_search" msgid="3091587249776033139">"Maghanap"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Mag-slide pataas para sa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Pindutin upang ipakita"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Huwag istorbohin"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d pa"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Nasa ibaba ang mga notification na hindi masyadong mahalaga"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"I-tap ulit upang buksan"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Mag-swipe pataas upang i-unlock"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Mag-swipe pakanan para sa telepono"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Mag-swipe pakaliwa para sa camera"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Hanggang sa i-off mo ito"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nagtsa-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang mapuno)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Bisita"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Bisita"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Sa loob ng isang minuto"</item>
<item quantity="other" msgid="6924190729213550991">"Sa loob ng %d (na) minuto"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Sa loob ng isang oras"</item>
<item quantity="other" msgid="5408537517529822157">"Sa loob ng %d (na) oras"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Naka-on ang tagatipid ng baterya"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Binawasan ang pagganap ng device."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Buksan ang mga setting ng tagatipid ng baterya"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 85ba8fe..7635c01 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Bildirim yok"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sürüyor"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Bildirimler"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Şarj cihazını takın"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Pil azalıyor."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Pil gücü düşük"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> kaldı"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> kaldı. Pil tasarrufu açık."</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB üzerinden şarj desteklenmiyor.\nYalnızca ürünle birlikte verilen şarj cihazını kullanın."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Pil kullanımı"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"USB şarjı desteklenmiyor."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Yalnızca ürünle birlikte verilen şarj cihazını kullanın."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Ayarlar"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Pil tasarrufu başlatılsın mı?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Başlat"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Pil tasarrufunu başlat"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Pil tasarrufu, pil ömrünü iyileştirmeye yardımcı olmak için cihazınızın performansını düşürür.\n\nCihazınız fişe takılıyken Pil tasarrufu devre dışı bırakılır."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ayarlar"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Kablosuz"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Uçak modu"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Açık."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Kapalı."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Bağlandı."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Bağlanıyor."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Cihaz)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Kapalı"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Parlaklık"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Otomatik Döndür"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Dönme Kilitlendi"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Dikey Görünüme Kilitlendi"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Yatay Görünüme Kilitlendi"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Otomatik döndür"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Döndürme kilitlendi"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Dikey"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Yatay"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Giriş Yöntemi"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Konum"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Konum Bilgisi Kapalı"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Bağlı Değil"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Yayınlama Ekranı"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Ekranı yayınla"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Parlaklık"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATİK"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Renkleri çevir"</string>
@@ -213,10 +218,13 @@
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Tethering"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Bildirimler"</string>
- <!-- no translation found for recents_empty_message (7883614615463619450) -->
- <skip />
+ <string name="recents_empty_message" msgid="7883614615463619450">"Yakın zamanda kullanılan uygulama yok"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Uygulama Bilgileri"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"ara"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ödeme alındı"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Şarj oluyor"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Tam şarj olmasına <xliff:g id="CHARGING_TIME">%s</xliff:g> kaldı"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Şarj olmuyor"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ağ izleniyor\nolabilir"</string>
<string name="description_target_search" msgid="3091587249776033139">"Ara"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için yukarı kaydırın."</string>
@@ -227,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Görüntülemek için dokunun"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Rahatsız etmeyin"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d adet daha"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Daha az acil bildirimler aşağıdadır"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Açmak için tekrar hafifçe vurun"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Kilidi açmak için hızlıca yukarı kaydırın"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Telefon için sağa kaydırın"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Kamera için sola kaydırın"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Siz bunu kapatana kadar"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Şarj oluyor (tamamen dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Misafir"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Misafir"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Bir dakika süreyle"</item>
<item quantity="other" msgid="6924190729213550991">"%d dakika süreyle"</item>
@@ -242,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Bir saat süreyle"</item>
<item quantity="other" msgid="5408537517529822157">"%d saat süreyle"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Pil tasarrufu açık"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Cihazın performansı düşürüldü."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Pil tasarrufu ayarlarını aç"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 7f66e72..12dd57e 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Немає сповіщень"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Поточні"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Сповіщення"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Підключіть зарядний пристрій"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Акумулятор розряджається."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Низький рівень заряду акумулятора"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"Залишилося <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Залишилося <xliff:g id="NUMBER">%d%%</xliff:g>. Режим заощадження заряду акумулятора ввімкнено."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Заряджання USB не підтримується.\nВикористовуйте лише наданий у комплекті зарядний пристрій."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Використання акумулятора"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Заряджання через USB не підтримується."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Використовуйте лише зарядний пристрій, який постачається в комплекті."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Налаштування"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Увімкнути режим заощадження заряду акумулятора?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Почати"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Увімкнути режим заощадження заряду акумулятора"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Щоб подовжити роботу акумулятора, буде знижено продуктивність пристрою.\n\nРежим заощадження заряду акумулятора вимкнеться, коли пристрій буде підключено до мережі живлення."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Налаштування"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим польоту"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Увімкнено."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Вимкнено."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Під’єднано."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"З’єднання."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (пристроїв: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth вимкнено"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Яскравість"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Обертати автоматично"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Обертання заблоковано"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Заблоковано в книжковій орієнтації"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Заблоковано в альбомній орієнтації"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Автоматичне обертання"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Обертання заблоковано"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Книжкова орієнтація"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Альбомна орієнтація"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Метод введення"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Місцезнаходження"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Місцезнаходження вимкнено"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Не під’єднано."</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Транслювати екран"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Транслювати екран"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яскравість"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТО"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Інвертувати кольори"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Немає останніх додатків"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Інформація про додаток"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заряджено"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Заряджається"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"До повного зарядження <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Не заряджається"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мережа може\nвідстежуватися"</string>
<string name="description_target_search" msgid="3091587249776033139">"Пошук"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Проведіть пальцем угору, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Торкніться, щоб показати"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Не турбувати"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"Ще %d"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Менше термінових сповіщень нижче"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Торкніться знову, щоб відкрити"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Проведіть пальцем угору, щоб розблокувати"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Проведіть пальцем праворуч, щоб скористатися телефоном"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Проведіть пальцем ліворуч, щоб скористатися камерою"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Доки ви не вимкнете"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного зарядження)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Гість"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"Додати гостя"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Протягом хвилини"</item>
<item quantity="other" msgid="6924190729213550991">"Протягом %d хв"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Протягом години"</item>
<item quantity="other" msgid="5408537517529822157">"Протягом %d год"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Режим заощадження заряду акумулятора ввімкнено"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Продуктивність пристрою знижено."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Відкрийте налаштування режиму заощадження заряду акумулятора"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 3ddea96..e15d3e5 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Không có thông báo nào"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Đang diễn ra"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Thông báo"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Cắm bộ sạc"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Pin đang yếu."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Pin yếu"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> còn lại"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"Còn lại <xliff:g id="NUMBER">%d%%</xliff:g>. Trình tiết kiệm pin đang bật."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Không hỗ trợ sạc qua USB.\nChỉ sử dụng bộ sạc được cung cấp."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Sử dụng pin"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Sạc qua USB không được hỗ trợ."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Chỉ sử dụng bộ sạc được cung cấp."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Cài đặt"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Khởi động trình tiết kiệm pin?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Bắt đầu"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Khởi động trình tiết kiệm pin"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Để giúp tăng tuổi thọ pin, trình tiết kiệm pin sẽ giảm hiệu suất của thiết bị.\n\nTrình tiết kiệm pin sẽ tắt khi thiết bị của bạn được cắm vào."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Cài đặt"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Chế độ trên máy bay"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Bật."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Tắt."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Đã kết nối."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Đang kết nối."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> thiết bị)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Đã tắt Bluetooth"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Độ sáng"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Tự động xoay"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Khóa xoay"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Đã khóa ở chế độ xoay dọc"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Đã khóa ở chế độ xoay ngang"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Tự động xoay"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Khóa xoay"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Dọc"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Ngang"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Phương thức nhập"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Vị trí"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Tắt vị trí"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Chưa được kết nối"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Truyền màn hình"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Màn hình truyền"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Độ sáng"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"TỰ ĐỘNG"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Đảo ngược màu"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Không có ứng dụng nào gần đây"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Thông tin ứng dụng"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"tìm kiếm"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Đã sạc"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Đang sạc"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> cho đến khi đầy"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Hiện không sạc"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mạng có thể\nđược giám sát"</string>
<string name="description_target_search" msgid="3091587249776033139">"Tìm kiếm"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Trượt lên để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Chạm để hiển thị"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Không làm phiền"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d thông báo khác"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Thông báo ít khẩn cấp hơn bên dưới"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Nhấn lại để mở"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Vuốt lên để mở khóa"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Vuốt sang phải để mở điện thoại"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Vuốt sang trái để mở máy ảnh"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Cho đến khi bạn tắt tính năng này"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Đang sạc (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho đến khi đầy)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Khách"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Khách"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Trong một phút"</item>
<item quantity="other" msgid="6924190729213550991">"Trong %d phút"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Trong một giờ"</item>
<item quantity="other" msgid="5408537517529822157">"Trong %d giờ"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Trình tiết kiệm pin đang bật"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Hiệu suất của thiết bị đã giảm."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Mở cài đặt trình tiết kiệm pin"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 934ac8c..cfd4fe9 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"无通知"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"正在进行的"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"请连接充电器"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"电池电量低。"</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"电池电量偏低"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"还剩 <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"电量还剩<xliff:g id="NUMBER">%d%%</xliff:g>。节电助手已启用。"</string>
<string name="invalid_charger" msgid="4549105996740522523">"不支持 USB 充电功能。\n只能使用随附的充电器充电。"</string>
- <string name="battery_low_why" msgid="7279169609518386372">"电量使用情况"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"不支持USB充电功能。"</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"仅限使用设备随附的充电器。"</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"设置"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"启动节电助手?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"启动"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"启动节电助手"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"为了延长电池的续航时间,节电助手会减降设备的性能。\n\n设备接通电源后,节电助手会自动停用。"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"设置"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WLAN"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"飞行模式"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"开启。"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"关闭。"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"已连接。"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"正在连接。"</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"蓝牙(<xliff:g id="NUMBER">%d</xliff:g> 台设备)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"蓝牙:关闭"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"亮度"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"自动旋转"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"屏幕方向:锁定"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"锁定为纵向"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"锁定为横向"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"自动旋转"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"屏幕方向:锁定"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"纵向"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"横向"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"输入法"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"位置信息"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"位置信息:关闭"</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"未连接"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"投射屏幕"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"投射屏幕"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自动"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"反色"</string>
@@ -218,6 +223,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"最近没有用过任何应用"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"应用信息"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"充电完成"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"正在充电"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"还需<xliff:g id="CHARGING_TIME">%s</xliff:g>才能充满"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"未在充电"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"网络可能会\n受到监控"</string>
<string name="description_target_search" msgid="3091587249776033139">"搜索"</string>
<string name="description_direction_up" msgid="7169032478259485180">"向上滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
@@ -228,13 +237,18 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"触摸即可显示"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"勿扰"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"还有%d条"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"不太紧急的通知会显示在下方"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"再次点按即可打开"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"向上滑动即可解锁"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"向右滑动可打开拨号界面"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"向左滑动可打开相机"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"直到您将其关闭"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"正在充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>才能充满)"</string>
+ <!-- no translation found for guest_nickname (8059989128963789678) -->
+ <skip />
+ <!-- no translation found for guest_new_guest (4259024453643879653) -->
+ <skip />
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"1分钟"</item>
<item quantity="other" msgid="6924190729213550991">"%d分钟"</item>
@@ -243,4 +257,7 @@
<item quantity="one" msgid="3480040795582254384">"1小时"</item>
<item quantity="other" msgid="5408537517529822157">"%d小时"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"节电助手已启用"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"设备性能已减降。"</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"打开节电助手设置"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 40b56fe..4b5cf08 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"無通知"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"持續進行"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"連接充電器"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"電池即將用盡。"</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"電量低"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"剩餘 <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"電量剩下 <xliff:g id="NUMBER">%d%%</xliff:g>,節約電池用量模式已啟用。"</string>
<string name="invalid_charger" msgid="4549105996740522523">"不支援 USB 充電。\n僅能使用隨附的充電器。"</string>
- <string name="battery_low_why" msgid="7279169609518386372">"電池使用情況"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"不支援 USB 充電功能。"</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"僅限使用裝置隨附的充電器。"</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"設定"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"啟動節約電池用量模式?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"開始"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"啟動節約電池用量模式"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"節約電池用量模式有助於延長電池壽命,但會降低裝置的效能。\n\n裝置接上電源時,節約電池用量模式會自動停用。"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"飛行模式"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"開啟。"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"關閉。"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"已連線。"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"連線中。"</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"藍牙 (<xliff:g id="NUMBER">%d</xliff:g> 部裝置)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"藍牙關閉"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"亮度"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"自動旋轉"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"已鎖定屏幕旋轉功能"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"已鎖定為直向"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"已鎖定為橫向"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"自動旋轉"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"輪流展示鎖定"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"直向"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"橫向"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"輸入法"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"位置"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"位置關閉"</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"未連線"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"放送螢幕"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"放送螢幕"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"反轉顏色"</string>
@@ -218,6 +223,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"沒有最近使用的應用程式"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資料"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已完成充電"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電中"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>後完成充電"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"非充電中"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網絡可能會\n受到監控"</string>
<string name="description_target_search" msgid="3091587249776033139">"搜尋"</string>
<string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
@@ -228,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"輕觸即可顯示"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"請勿騷擾"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"還有 %d 個"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"還有 <xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g> 則通知"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"不太緊急的通知會在下方顯示"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"再次輕按即可開啟"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"向上快速滑動即可解鎖"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"向右快速滑動即可使用手機功能"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"向左快速滑動即可使用相機功能"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"直至您關閉這項設定"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"訪客"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"新增訪客"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"1 分鐘"</item>
<item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item>
@@ -243,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"1 小時"</item>
<item quantity="other" msgid="5408537517529822157">"%d 小時"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"節約電池用量模式已啟用"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"裝置效能已降低。"</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"開啟節約電池用量設定"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index c1a48c4..a780ad1 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"沒有通知"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"進行中"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"連接充電器"</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"電池電量即將不足。"</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"電池電力不足"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"還剩 <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"電力剩下 <xliff:g id="NUMBER">%d%%</xliff:g>,節約耗電量模式已啟用。"</string>
<string name="invalid_charger" msgid="4549105996740522523">"不支援 USB 充電。\n僅能使用隨附的充電器。"</string>
- <string name="battery_low_why" msgid="7279169609518386372">"電池使用狀況"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"不支援 USB 充電功能。"</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"僅限使用裝置隨附的充電器。"</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"設定"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"啟動節約耗電量模式?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"啟動"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"啟動節約耗電量模式"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"節約耗電量模式有助於延長電池續航力,但會讓裝置的效能降低。\n\n裝置接上電源時,節約耗電量模式會自動停用。"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"飛行模式"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"開啟。"</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"關閉。"</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"已連線。"</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"連線中。"</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -189,10 +194,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"藍牙 (<xliff:g id="NUMBER">%d</xliff:g> 個裝置)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"關閉藍牙"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"亮度"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"自動旋轉"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"已鎖定螢幕旋轉功能"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"已鎖定為縱向"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"已鎖定為橫向"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"自動旋轉"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"已鎖定旋轉"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"縱向"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"橫向"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"輸入法"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"定位"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"定位服務已關閉"</string>
@@ -206,7 +211,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"未連線"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"投放螢幕"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"投放螢幕"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"反轉顏色"</string>
@@ -218,6 +223,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"沒有最近使用的應用程式"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資訊"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已充飽"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"充電中"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>後充飽"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"未充電"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網路可能\n受到監控"</string>
<string name="description_target_search" msgid="3091587249776033139">"搜尋"</string>
<string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
@@ -228,13 +237,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"輕觸即可顯示"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"請勿打擾"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"還有 %d 則"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"還有 <xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g> 則通知"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"較不緊急的通知會顯示在下方"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"再次輕按即可開啟"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"向上滑動即可解鎖"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"向左滑動可使用手機功能"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"向左滑動可使用相機功能"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"手動關閉這項設定前一律啟用"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後充飽)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"訪客"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"新增訪客"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"1 分鐘"</item>
<item quantity="other" msgid="6924190729213550991">"%d 分鐘"</item>
@@ -243,4 +255,7 @@
<item quantity="one" msgid="3480040795582254384">"1 小時"</item>
<item quantity="other" msgid="5408537517529822157">"%d 小時"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"節約耗電量模式已啟用"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"裝置效能已降低。"</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"開啟節約耗電量設定"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index af49a7f..8458ca8 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -32,11 +32,17 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Azikho izaziso"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Okuqhubekayo"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Izaziso"</string>
- <string name="battery_low_title" msgid="2783104807551211639">"Xhuma ishaja."</string>
- <string name="battery_low_subtitle" msgid="1752040062087829196">"Ibhetri iya ngokuphela."</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Ibhethri liphansi"</string>
<string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> okusele"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> esele. Isilondolozi Sebhethri sivuliwe."</string>
<string name="invalid_charger" msgid="4549105996740522523">"Ukushaja i-USB akusekelwe.\nSebenzisa kuphela ishaja enikeziwe."</string>
- <string name="battery_low_why" msgid="7279169609518386372">"Ukusebenzisa ibhetri"</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Ukushaja kwe-USB akusekelwe."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Sebenzisa kuphela ishaja enikeziwe."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Izilungiselelo"</string>
+ <string name="battery_saver_confirmation_title" msgid="5987726159603849352">"Qala isilondolozi sebhethri?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7283108887345688413">"Qala"</string>
+ <string name="battery_saver_start_action" msgid="7245333922937402896">"Qala isilondolozi sebhethri"</string>
+ <string name="battery_saver_confirmation_text" msgid="8417584516834617662">"Ukusiza ukuthuthukisa impilo yebhethri, Isilondolozi Sebhethri sizonciphisa ukusebenza kwedivayisi yakho.\n\nIsilondolozi Sebhethri sizokhutshazwa uma idivayisi yakho ixhunywa."</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Izilungiselelo"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"I-Wi-Fi"</string>
<string name="status_bar_settings_airplane" msgid="4879879698500955300">"Imodi yendiza"</string>
@@ -120,8 +126,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"Vula."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"Vala."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"Ixhunyiwe."</string>
- <!-- no translation found for accessibility_desc_connecting (3812924520316280149) -->
- <skip />
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Iyaxhuma."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"I-HSPA"</string>
@@ -187,10 +192,10 @@
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"I-Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> amadivayisi)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"I-Bluetooth ivaliwe"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Ukugqama"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="336054930362580584">"Ukuphendula ngokuzenzakalela"</string>
- <string name="quick_settings_rotation_locked_label" msgid="8058646447242565486">"Ukuphendula kukhiyiwe"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="1553131290066230775">"Kukhiyelwe ekumeni ngobude"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="7216265671276086593">"Kukhiyelwe ekwakhiweni kwezwe"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Ukuphenduka okuzenzakalelayo"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Ukuphenduka kukhiyiwe"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Ukuma ngobude"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Ndlaleka okubanzi"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Indlela yokungenayo"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Indawo"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Indawo ivaliwe"</string>
@@ -204,7 +209,7 @@
<string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Akuxhunyiwe"</string>
<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_remote_display_no_connection_label" msgid="372107699274391290">"Isikrini sabalingisi"</string>
+ <string name="quick_settings_remote_display_no_connection_label" msgid="7482103121002965053">"Isikrini sabadlali"</string>
<string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ukugqama"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OKUZENZAKALELAYO"</string>
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Faka imibala"</string>
@@ -216,6 +221,10 @@
<string name="recents_empty_message" msgid="7883614615463619450">"Azikho izinhlelo zokusebenza zakamuva"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Ulwazi lohlelo lokusebenza"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kushajiwe"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Iyashaja"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ize igcwale"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ayishaji"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Kungenzeka inethiwekhi\niqashiwe"</string>
<string name="description_target_search" msgid="3091587249776033139">"Sesha"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Shelelisela ngenhla ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -226,13 +235,16 @@
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Thinta ukuze ubonise"</string>
<string name="zen_mode_title" msgid="8793432092004749188">"Ungaphazamisi"</string>
- <plurals name="keyguard_more_overflow_text">
- <item quantity="other" msgid="9180696159506883684">"%d okuningi"</item>
- </plurals>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Izaziso ezingasheshi kakhulu ezingezansi"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Thepha futhi ukuze uvule"</string>
<string name="keyguard_unlock" msgid="8043466894212841998">"Swayiphela phezulu ukuze uvule"</string>
+ <string name="phone_hint" msgid="3101468054914424646">"Swayiphela ngakwesokudla ukuze uthole ifoni"</string>
+ <string name="camera_hint" msgid="5241441720959174226">"Swayiphela ngakwesokunxele ukuze uthole ikhamela"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Uze uvale lokhu"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Iyashaja (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Isihambeli"</string>
+ <string name="guest_new_guest" msgid="4259024453643879653">"+ Isihambeli"</string>
<plurals name="zen_mode_duration_minutes">
<item quantity="one" msgid="9040808414992812341">"Iminithi elilodwa"</item>
<item quantity="other" msgid="6924190729213550991">"Amaminithi angu-%d"</item>
@@ -241,4 +253,7 @@
<item quantity="one" msgid="3480040795582254384">"Ihora elilodwa"</item>
<item quantity="other" msgid="5408537517529822157">"Amahora angu-%d"</item>
</plurals>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Isilondolozi sebhethri sivuliwe"</string>
+ <string name="battery_saver_notification_text" msgid="7796554871101546872">"Ukusebenza kwedivayisi kwehlisiwe."</string>
+ <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"Vula izilungiselelo zesilondolozi sebhethri"</string>
</resources>
diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml
index 1ce4983..6628f3b 100644
--- a/packages/SystemUI/res/values/arrays.xml
+++ b/packages/SystemUI/res/values/arrays.xml
@@ -42,13 +42,11 @@
<!-- BatteryMeterView parameters -->
<array name="batterymeter_color_levels">
- <item>4</item>
<item>15</item>
<item>100</item>
</array>
<array name="batterymeter_color_values">
<item>#FFFF3300</item>
- <item>#FFFF3300</item>
<item>#FFFFFFFF</item>
</array>
<array name="batterymeter_bolt_points">
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 34cfbe8e..8c1a9c7 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -29,7 +29,6 @@
<drawable name="status_bar_notification_row_background_color">#ff090909</drawable>
<color name="notification_list_shadow_top">#80000000</color>
<drawable name="recents_callout_line">#99ffffff</drawable>
- <drawable name="notification_item_background_legacy_color">#ffaaaaaa</drawable>
<drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
<color name="batterymeter_frame_color">#66FFFFFF</color><!-- 40% white -->
<color name="batterymeter_charge_color">#FFFFFFFF</color>
@@ -42,24 +41,10 @@
<color name="qs_tile_divider">#29ffffff</color><!-- 16% white -->
<color name="qs_tile_text">#FFFFFFFF</color>
<color name="status_bar_clock_color">#FFFFFFFF</color>
- <drawable name="notification_item_background_color">#ff111111</drawable>
- <drawable name="notification_item_background_color_pressed">#ff454545</drawable>
<!-- Tint color for the content on the notification overflow card. -->
<color name="keyguard_overflow_content_color">#ff686868</color>
- <!-- The color of the red speed bump dot -->
- <color name="speed_bump_dot_red">#ffd50000</color>
-
- <!-- The color of the blue speed bump dot -->
- <color name="speed_bump_dot_blue">#ff2962ff</color>
-
- <!-- The color of the yellow speed bump dot -->
- <color name="speed_bump_dot_yellow">#ffffd600</color>
-
- <!-- The color of the green speed bump dot -->
- <color name="speed_bump_dot_green">#ff00c853</color>
-
<!-- The default recents task bar background color. -->
<color name="recents_task_bar_default_background_color">#e6444444</color>
<!-- The default recents task bar text color. -->
@@ -77,7 +62,7 @@
<color name="keyguard_affordance">#ffffffff</color>
- <!-- Our quantum color palette (deep teal) -->
+ <!-- Our material color palette (deep teal) -->
<color name="primary_color">#ff7fcac3</color>
<color name="background_color_1">#ff384248</color>
<color name="background_color_1_press">#ff54656e</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 79a1df4..c8851dc 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -108,17 +108,25 @@
<!-- milliseconds before the heads up notification accepts touches. -->
<integer name="heads_up_sensitivity_delay">700</integer>
+ <!-- The duration in seconds to wait before the dismiss buttons are shown. -->
+ <integer name="recents_task_bar_dismiss_delay_seconds">3</integer>
<!-- The min animation duration for animating views that are currently visible. -->
<integer name="recents_filter_animate_current_views_min_duration">175</integer>
<!-- The min animation duration for animating views that are newly visible. -->
<integer name="recents_filter_animate_new_views_min_duration">125</integer>
<!-- The min animation duration for animating the task bar in. -->
- <integer name="recents_animate_task_bar_enter_duration">250</integer>
+ <integer name="recents_animate_task_bar_enter_duration">275</integer>
<!-- The animation delay for animating the first task in. This should roughly be the animation
duration of the transition in to recents. -->
<integer name="recents_animate_task_bar_enter_delay">225</integer>
<!-- The min animation duration for animating the task bar out. -->
+ <integer name="recents_animate_task_exit_to_home_duration">225</integer>
+ <!-- The min animation duration for animating the task bar out. -->
<integer name="recents_animate_task_bar_exit_duration">125</integer>
+ <!-- The min animation duration for animating the task in when transitioning from home. -->
+ <integer name="recents_animate_task_enter_from_home_duration">275</integer>
+ <!-- The animation stagger to apply to each task animation when transitioning from home. -->
+ <integer name="recents_animate_task_enter_from_home_delay">10</integer>
<!-- The min animation duration for animating the nav bar scrim in. -->
<integer name="recents_nav_bar_scrim_enter_duration">400</integer>
<!-- The animation duration for animating the removal of a task view. -->
@@ -141,5 +149,10 @@
<!-- Wait on the touch feedback this long before performing an action. -->
<integer name="feedback_start_delay">300</integer>
+
+ <!-- Set to true to enable the classic notification ticker that scrolls
+ Notification.tickerText across the status bar for what seems like an
+ eternity. -->
+ <bool name="enable_ticker">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 35bc7e3..8b8c126 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -235,9 +235,6 @@
<!-- The amount of highlight to make on each task view. -->
<dimen name="recents_task_view_highlight">1dp</dimen>
- <!-- The amount of space a user has to scroll to dismiss any info panes. -->
- <dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen>
-
<!-- The height of the search bar space. -->
<dimen name="recents_search_bar_space_height">64dp</dimen>
@@ -275,14 +272,8 @@
<!-- The minimum amount of top overscroll to go to the quick settings. -->
<dimen name="min_top_overscroll_to_qs">36dp</dimen>
- <!-- The height of the collapsed speed bump view. -->
- <dimen name="speed_bump_height_collapsed">24dp</dimen>
-
- <!-- The padding inset the explanation text needs compared to the collapsed height -->
- <dimen name="speed_bump_text_padding_inset">10dp</dimen>
-
- <!-- The height of the speed bump dots. -->
- <dimen name="speed_bump_dots_height">5dp</dimen>
+ <!-- The height of the speed bump view. -->
+ <dimen name="speed_bump_height">16dp</dimen>
<!-- The total height of the stack in its collapsed size (i.e. when quick settings is open) -->
<dimen name="collapsed_stack_height">94dp</dimen>
@@ -301,12 +292,12 @@
<!-- The fraction of the screen height where the clock on the Keyguard has its center. The
max value is used when no notifications are displaying, and the min value is when the
highest possible number of notifications are showing. -->
- <fraction name="keyguard_clock_y_fraction_max">29.5%</fraction>
- <fraction name="keyguard_clock_y_fraction_min">18%</fraction>
+ <fraction name="keyguard_clock_y_fraction_max">32.5%</fraction>
+ <fraction name="keyguard_clock_y_fraction_min">19.8%</fraction>
<!-- The margin between the clock and the notifications on Keyguard. See
keyguard_clock_height_fraction_* for the difference between min and max.-->
- <dimen name="keyguard_clock_notifications_margin_min">22dp</dimen>
+ <dimen name="keyguard_clock_notifications_margin_min">24dp</dimen>
<dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
<dimen name="heads_up_window_height">250dp</dimen>
@@ -338,4 +329,7 @@
<!-- The width of the region on the left/right edge of the screen for performing the camera/
phone hints. -->
<dimen name="edge_tap_area_width">48dp</dimen>
+
+ <!-- end margin for multi user switch in expanded quick settings -->
+ <dimen name="multi_user_switch_expanded_margin">8dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/internal.xml b/packages/SystemUI/res/values/internal.xml
index ddaab942..7b93d31 100644
--- a/packages/SystemUI/res/values/internal.xml
+++ b/packages/SystemUI/res/values/internal.xml
@@ -17,6 +17,6 @@
<resources>
<dimen name="status_bar_height">@*android:dimen/status_bar_height</dimen>
<dimen name="navigation_bar_height">@*android:dimen/navigation_bar_height</dimen>
- <drawable name="notification_quantum_bg">@*android:drawable/notification_quantum_bg</drawable>
+ <drawable name="notification_material_bg">@*android:drawable/notification_material_bg</drawable>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index de297e5..e5499ee 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -59,25 +59,43 @@
<string name="status_bar_latest_events_title">Notifications</string>
<!-- When the battery is low, this is displayed to the user in a dialog. The title of the low battery alert. [CHAR LIMIT=NONE]-->
- <string name="battery_low_title">Connect charger</string>
-
- <!-- When the battery is low, this is displayed to the user in a dialog. The subtitle of the low battery alert. [CHAR LIMIT=NONE] -->
- <string name="battery_low_subtitle">The battery is getting low.</string>
+ <string name="battery_low_title">Battery is low</string>
<!-- A message that appears when the battery level is getting low in a dialog. This is
appened to the subtitle of the low battery alert. "number" is the percentage of battery
remaining [CHAR LIMIT=none]-->
<string name="battery_low_percent_format"><xliff:g id="number">%d%%</xliff:g> remaining</string>
+ <!-- Same as battery_low_percent_format, with a notice about battery saver if on. [CHAR LIMIT=none]-->
+ <string name="battery_low_percent_format_saver_started"><xliff:g id="number">%d%%</xliff:g> remaining. Battery saver is on.</string>
+
<!-- A message that appears when a USB charger is plugged in and the device does not
support charging on it. That is, a charger that fits into the USB port and goes into
a wall socket, not into a computer. (This happens because some devices require more
current than the USB spec allows. [CHAR LIMIT=NONE] -->
<string name="invalid_charger">USB charging not supported.\nUse only the supplied charger.</string>
+ <!-- First line of invalid_charger, used in the notification form. [CHAR LIMIT=NONE]-->
+ <string name="invalid_charger_title">USB charging not supported.</string>
+
+ <!-- Second line of invalid_charger, used in the notification form. [CHAR LIMIT=NONE]-->
+ <string name="invalid_charger_text">Use only the supplied charger.</string>
+
<!-- When the battery is low, this is the label of the button to go to the
power usage activity to find out what drained the battery. [CHAR LIMIT=30] -->
- <string name="battery_low_why">Battery use</string>
+ <string name="battery_low_why">Settings</string>
+
+ <!-- Battery saver confirmation dialog title [CHAR LIMIT=NONE]-->
+ <string name="battery_saver_confirmation_title">Start battery saver?</string>
+
+ <!-- Battery saver confirmation dialog ok text [CHAR LIMIT=40]-->
+ <string name="battery_saver_confirmation_ok">Start</string>
+
+ <!-- Battery saver notification action [CHAR LIMIT=NONE]-->
+ <string name="battery_saver_start_action">Start battery saver</string>
+
+ <!-- Battery saver confirmation dialog text [CHAR LIMIT=NONE]-->
+ <string name="battery_saver_confirmation_text">To help improve battery life, Battery saver will reduce your device’s performance.\n\nBattery saver will be disabled when your device is plugged in.</string>
<!-- Name of the button that links to the Settings app. [CHAR LIMIT=NONE] -->
<string name="status_bar_settings_settings_button">Settings</string>
@@ -531,6 +549,18 @@
<string name="recents_search_bar_label">search</string>
+ <!-- Expanded Status Bar Header: Battery Charged [CHAR LIMIT=40] -->
+ <string name="expanded_header_battery_charged">Charged</string>
+
+ <!-- Expanded Status Bar Header: Charging, no known time [CHAR LIMIT=40] -->
+ <string name="expanded_header_battery_charging">Charging</string>
+
+ <!-- Expanded Status Bar Header: Charging, showing time left until charged [CHAR LIMIT=40] -->
+ <string name="expanded_header_battery_charging_with_time"><xliff:g id="charging_time" example="2 hrs 25 min">%s</xliff:g> until full</string>
+
+ <!-- Expanded Status Bar Header: Not charging [CHAR LIMIT=40] -->
+ <string name="expanded_header_battery_not_charging">Not charging</string>
+
<!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. -->
<string name="battery_meter_very_low_overlay_symbol">!</string>
@@ -584,6 +614,13 @@
<!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]-->
<string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
+ <!-- Related to user switcher --><skip/>
+ <!-- Name for the guest user -->
+ <string name="guest_nickname">Guest</string>
+
+ <!-- Label for adding a new guest -->
+ <string name="guest_new_guest">+ Guest</string>
+
<!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] -->
<plurals name="zen_mode_duration_minutes">
<item quantity="one">For one minute</item>
@@ -595,4 +632,13 @@
<item quantity="one">For one hour</item>
<item quantity="other">For %d hours</item>
</plurals>
+
+ <!-- Battery saver notification title. [CHAR LIMIT=60]-->
+ <string name="battery_saver_notification_title">Battery saver is on</string>
+
+ <!-- Battery saver notification text. [CHAR LIMIT=60] -->
+ <string name="battery_saver_notification_text">Device performance is reduced.</string>
+
+ <!-- Battery saver notification action text. [CHAR LIMIT=60] -->
+ <string name="battery_saver_notification_action_text">Open battery saver settings</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 4c269a2..c117eba 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -63,24 +63,36 @@
<style name="TextAppearance.StatusBar.Clock" parent="@*android:style/TextAppearance.StatusBar.Icon">
<!-- Note: must be dp to fit in status bar -->
<item name="android:textSize">16dp</item>
- <item name="android:textStyle">normal</item>
+ <item name="android:fontFamily">sans-serif-medium</item>
<item name="android:textColor">@color/status_bar_clock_color</item>
</style>
<style name="TextAppearance.StatusBar.Expanded" parent="@*android:style/TextAppearance.StatusBar" />
<style name="TextAppearance.StatusBar.Expanded.Clock">
- <item name="android:textSize">18dp</item>
+ <item name="android:textSize">16dp</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">#ffffff</item>
</style>
<style name="TextAppearance.StatusBar.Expanded.Date">
+ <item name="android:textSize">14dp</item>
+ <item name="android:textStyle">normal</item>
+ <item name="android:textColor">#99ffffff</item>
+ </style>
+
+ <style name="TextAppearance.StatusBar.Expanded.AboveDateTime">
<item name="android:textSize">12dp</item>
<item name="android:textStyle">normal</item>
- <item name="android:textColor">#afb3b6</item>
+ <item name="android:textColor">#99ffffff</item>
</style>
+ <style name="TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"
+ parent="TextAppearance.StatusBar.Expanded.AboveDateTime" />
+
+ <style name="TextAppearance.StatusBar.Expanded.ChargingInfo"
+ parent="TextAppearance.StatusBar.Expanded.AboveDateTime" />
+
<style name="TextAppearance.StatusBar.Expanded.Network" parent="@style/TextAppearance.StatusBar.Expanded.Date">
<item name="android:textColor">#999999</item>
</style>
@@ -214,7 +226,7 @@
<item name="android:colorControlActivated">#ffffffff</item>
</style>
- <style name="BorderlessButton" parent="@android:style/Widget.Quantum.Button.Borderless" />
+ <style name="BorderlessButton" parent="@android:style/Widget.Material.Button.Borderless" />
<style name="BorderlessButton.Tiny">
<item name="android:minHeight">12dip</item>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 19d06be..5e48258 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -25,8 +25,6 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.os.BatteryManager;
@@ -44,7 +42,6 @@
private static final boolean SHOW_100_PERCENT = false;
private static final int FULL = 96;
- private static final int EMPTY = 4;
private static final float SUBPIXEL = 0.4f; // inset rects for softer edges
private static final float BOLT_LEVEL_THRESHOLD = 0.3f; // opaque bolt below this fraction
@@ -58,6 +55,7 @@
private int mHeight;
private int mWidth;
private String mWarningString;
+ private final int mCriticalLevel;
private final int mChargeColor;
private final float[] mBoltPoints;
private final Path mBoltPath = new Path();
@@ -197,6 +195,8 @@
mShowPercent = ENABLE_PERCENT && 0 != Settings.System.getInt(
context.getContentResolver(), "status_bar_show_battery_percent", 0);
mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
+ mCriticalLevel = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_criticalBatteryWarningLevel);
mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mFramePaint.setColor(frameColor);
@@ -303,7 +303,7 @@
if (level >= FULL) {
drawFrac = 1f;
- } else if (level <= EMPTY) {
+ } else if (level <= mCriticalLevel) {
drawFrac = 0f;
}
@@ -360,7 +360,7 @@
boolean pctOpaque = false;
float pctX = 0, pctY = 0;
String pctText = null;
- if (!tracker.plugged && level > EMPTY && mShowPercent
+ if (!tracker.plugged && level > mCriticalLevel && mShowPercent
&& !(tracker.level == 100 && !SHOW_100_PERCENT)) {
mTextPaint.setColor(getColorForLevel(level));
mTextPaint.setTextSize(height *
@@ -390,7 +390,7 @@
c.drawPath(mShapePath, mBatteryPaint);
if (!tracker.plugged) {
- if (level <= EMPTY) {
+ if (level <= mCriticalLevel) {
// draw the warning text
final float x = mWidth * 0.5f;
final float y = (mHeight + mWarningTextHeight) * 0.48f;
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 7c85712..9650435 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -20,9 +20,14 @@
import android.view.View;
public interface RecentsComponent {
+ public interface Callbacks {
+ public void onVisibilityChanged(boolean visible);
+ }
+
void showRecents(boolean triggeredFromAltTab, View statusBarView);
void hideRecents(boolean triggeredFromAltTab);
void toggleRecents(Display display, int layoutDirection, View statusBarView);
void preloadRecents();
void cancelPreloadingRecents();
+ void setCallback(Callbacks cb);
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
index feec87c..2943494 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
@@ -16,6 +16,7 @@
package com.android.systemui.power;
+import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Context;
@@ -25,13 +26,13 @@
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
-import android.view.View;
+import android.view.ContextThemeWrapper;
import android.view.WindowManager;
-import android.widget.TextView;
import com.android.systemui.R;
@@ -46,13 +47,14 @@
private int mBatteryLevel;
private int mBucket;
private long mScreenOffTime;
+ private boolean mSaver;
+ private int mSaverTriggerLevel;
private AlertDialog mInvalidChargerDialog;
private AlertDialog mLowBatteryDialog;
- private TextView mBatteryLevelTextView;
public PowerDialogWarnings(Context context) {
- mContext = context;
+ mContext = new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault_Light);
}
@Override
@@ -77,7 +79,7 @@
@Override
public void updateLowBatteryWarning() {
- if (mBatteryLevelTextView != null) {
+ if (mLowBatteryDialog != null) {
showLowBatteryWarning(false /*playSound*/);
}
}
@@ -93,27 +95,22 @@
@Override
public void showLowBatteryWarning(boolean playSound) {
Slog.i(TAG,
- ((mBatteryLevelTextView == null) ? "showing" : "updating")
+ ((mLowBatteryDialog == null) ? "showing" : "updating")
+ " low battery warning: level=" + mBatteryLevel
+ " [" + mBucket + "]");
- CharSequence levelText = mContext.getString(
- R.string.battery_low_percent_format, mBatteryLevel);
+ final int textRes = mSaver ? R.string.battery_low_percent_format_saver_started
+ : R.string.battery_low_percent_format;
+ final CharSequence levelText = mContext.getString(textRes, mBatteryLevel);
- if (mBatteryLevelTextView != null) {
- mBatteryLevelTextView.setText(levelText);
+ if (mLowBatteryDialog != null) {
+ mLowBatteryDialog.setMessage(levelText);
} else {
- View v = View.inflate(mContext, R.layout.battery_low, null);
- mBatteryLevelTextView = (TextView)v.findViewById(R.id.level_percent);
-
- mBatteryLevelTextView.setText(levelText);
-
AlertDialog.Builder b = new AlertDialog.Builder(mContext);
- b.setCancelable(true);
- b.setTitle(R.string.battery_low_title);
- b.setView(v);
- b.setIconAttribute(android.R.attr.alertDialogIcon);
- b.setPositiveButton(android.R.string.ok, null);
+ b.setCancelable(true);
+ b.setTitle(R.string.battery_low_title);
+ b.setMessage(levelText);
+ b.setPositiveButton(android.R.string.ok, null);
final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
@@ -125,6 +122,11 @@
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
+ try {
+ ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+ } catch (RemoteException e) {
+ // we tried
+ }
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
dismissLowBatteryWarning();
}
@@ -136,10 +138,9 @@
@Override
public void onDismiss(DialogInterface dialog) {
mLowBatteryDialog = null;
- mBatteryLevelTextView = null;
}
});
- d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
d.getWindow().getAttributes().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
d.show();
@@ -198,21 +199,32 @@
dismissLowBatteryWarning();
AlertDialog.Builder b = new AlertDialog.Builder(mContext);
- b.setCancelable(true);
- b.setMessage(R.string.invalid_charger);
- b.setIconAttribute(android.R.attr.alertDialogIcon);
- b.setPositiveButton(android.R.string.ok, null);
+ b.setCancelable(true);
+ b.setTitle(R.string.invalid_charger_title);
+ b.setMessage(R.string.invalid_charger_text);
+ b.setPositiveButton(android.R.string.ok, null);
AlertDialog d = b.create();
d.setOnDismissListener(new DialogInterface.OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
mInvalidChargerDialog = null;
- mBatteryLevelTextView = null;
}
});
- d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+ d.getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
d.show();
mInvalidChargerDialog = d;
}
+
+ @Override
+ public void showSaverMode(boolean mode) {
+ mSaver = mode;
+ }
+
+ @Override
+ public void setSaverTrigger(int level) {
+ mSaverTriggerLevel = level;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
new file mode 100644
index 0000000..c3ba349
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -0,0 +1,389 @@
+/*
+ * 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.systemui.power;
+
+import android.app.AlertDialog;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Slog;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+import java.io.PrintWriter;
+
+public class PowerNotificationWarnings implements PowerUI.WarningsUI {
+ private static final String TAG = PowerUI.TAG + ".Notification";
+ private static final boolean DEBUG = PowerUI.DEBUG;
+
+ private static final String TAG_NOTIFICATION = "low_battery";
+ private static final int ID_NOTIFICATION = 100;
+ private static final int AUTO_DISMISS_MS = 10000;
+
+ private static final int SHOWING_NOTHING = 0;
+ private static final int SHOWING_WARNING = 1;
+ private static final int SHOWING_SAVER = 2;
+ private static final int SHOWING_INVALID_CHARGER = 3;
+ private static final String[] SHOWING_STRINGS = {
+ "SHOWING_NOTHING",
+ "SHOWING_WARNING",
+ "SHOWING_SAVER",
+ "SHOWING_INVALID_CHARGER",
+ };
+
+ private static final String ACTION_SHOW_FALLBACK_WARNING = "PNW.warningFallback";
+ private static final String ACTION_SHOW_FALLBACK_CHARGER = "PNW.chargerFallback";
+ private static final String ACTION_SHOW_BATTERY_SETTINGS = "PNW.batterySettings";
+ private static final String ACTION_START_SAVER = "PNW.startSaver";
+
+ private final Context mContext;
+ private final Context mLightContext;
+ private final NotificationManager mNoMan;
+ private final Handler mHandler = new Handler();
+ private final PowerDialogWarnings mFallbackDialogs;
+ private final Receiver mReceiver = new Receiver();
+ private final Intent mOpenBatterySettings = settings(Intent.ACTION_POWER_USAGE_SUMMARY);
+ private final Intent mOpenSaverSettings = settings(Settings.ACTION_BATTERY_SAVER_SETTINGS);
+
+ private int mBatteryLevel;
+ private int mBucket;
+ private long mScreenOffTime;
+ private int mShowing;
+
+ private boolean mSaver;
+ private int mSaverTriggerLevel;
+ private boolean mWarning;
+ private boolean mPlaySound;
+ private boolean mInvalidCharger;
+
+ public PowerNotificationWarnings(Context context) {
+ mContext = context;
+ mLightContext = new ContextThemeWrapper(mContext,
+ android.R.style.Theme_DeviceDefault_Light);
+ mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ mFallbackDialogs = new PowerDialogWarnings(context);
+ mReceiver.init();
+ }
+
+ @Override
+ public void dump(PrintWriter pw) {
+ pw.print("mSaver="); pw.println(mSaver);
+ pw.print("mWarning="); pw.println(mWarning);
+ pw.print("mPlaySound="); pw.println(mPlaySound);
+ pw.print("mInvalidCharger="); pw.println(mInvalidCharger);
+ pw.print("mShowing="); pw.println(SHOWING_STRINGS[mShowing]);
+ }
+
+ @Override
+ public void update(int batteryLevel, int bucket, long screenOffTime) {
+ mBatteryLevel = batteryLevel;
+ mBucket = bucket;
+ mScreenOffTime = screenOffTime;
+ mFallbackDialogs.update(batteryLevel, bucket, screenOffTime);
+ }
+
+ @Override
+ public void showSaverMode(boolean mode) {
+ mSaver = mode;
+ updateNotification();
+ }
+
+ @Override
+ public void setSaverTrigger(int level) {
+ mSaverTriggerLevel = level;
+ updateNotification();
+ }
+
+ private void updateNotification() {
+ if (DEBUG) Slog.d(TAG, "updateNotification mWarning=" + mWarning
+ + " mSaver=" + mSaver + " mInvalidCharger=" + mInvalidCharger);
+ if (mInvalidCharger) {
+ showInvalidChargerNotification();
+ mShowing = SHOWING_INVALID_CHARGER;
+ } else if (mWarning) {
+ showWarningNotification();
+ mShowing = SHOWING_WARNING;
+ } else if (mSaver) {
+ showSaverNotification();
+ mShowing = SHOWING_SAVER;
+ } else {
+ mNoMan.cancel(TAG_NOTIFICATION, ID_NOTIFICATION);
+ mShowing = SHOWING_NOTHING;
+ }
+ }
+
+ private void showInvalidChargerNotification() {
+ final Notification.Builder nb = new Notification.Builder(mContext)
+ .setSmallIcon(R.drawable.ic_power_low)
+ .setShowWhen(false)
+ .setOngoing(true)
+ .setContentTitle(mContext.getString(R.string.invalid_charger_title))
+ .setContentText(mContext.getString(R.string.invalid_charger_text))
+ .setPriority(Notification.PRIORITY_MAX)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setFullScreenIntent(pendingBroadcast(ACTION_SHOW_FALLBACK_CHARGER), true);
+ final Notification n = nb.build();
+ if (n.headsUpContentView != null) {
+ n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
+ }
+ mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.CURRENT);
+ }
+
+ private void showWarningNotification() {
+ final int textRes = mSaver ? R.string.battery_low_percent_format_saver_started
+ : R.string.battery_low_percent_format;
+ final Notification.Builder nb = new Notification.Builder(mContext)
+ .setSmallIcon(R.drawable.ic_power_low)
+ .setShowWhen(false)
+ .setContentTitle(mContext.getString(R.string.battery_low_title))
+ .setContentText(mContext.getString(textRes, mBatteryLevel))
+ .setOngoing(true)
+ .setPriority(Notification.PRIORITY_MAX)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setFullScreenIntent(pendingBroadcast(ACTION_SHOW_FALLBACK_WARNING), true);
+ if (hasBatterySettings()) {
+ nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
+ }
+ if (!mSaver && mSaverTriggerLevel <= 0) {
+ nb.addAction(R.drawable.ic_power_saver,
+ mContext.getString(R.string.battery_saver_start_action),
+ pendingBroadcast(ACTION_START_SAVER));
+ }
+ if (mPlaySound) {
+ attachLowBatterySound(nb);
+ }
+ final Notification n = nb.build();
+ if (n.headsUpContentView != null) {
+ n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
+ }
+ mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.CURRENT);
+ }
+
+ private void showSaverNotification() {
+ final Notification.Builder nb = new Notification.Builder(mContext)
+ .setSmallIcon(R.drawable.ic_power_saver)
+ .setContentTitle(mContext.getString(R.string.battery_saver_notification_title))
+ .setContentText(mContext.getString(R.string.battery_saver_notification_text))
+ .setOngoing(true)
+ .setShowWhen(false)
+ .setCategory(Notification.CATEGORY_SYSTEM);
+ if (hasSaverSettings()) {
+ nb.addAction(0,
+ mContext.getString(R.string.battery_saver_notification_action_text),
+ pendingActivity(mOpenSaverSettings));
+ nb.setContentIntent(pendingActivity(mOpenSaverSettings));
+ }
+ mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, nb.build(), UserHandle.CURRENT);
+ }
+
+ private PendingIntent pendingActivity(Intent intent) {
+ return PendingIntent.getActivityAsUser(mContext,
+ 0, intent, 0, null, UserHandle.CURRENT);
+ }
+
+ private PendingIntent pendingBroadcast(String action) {
+ return PendingIntent.getBroadcastAsUser(mContext,
+ 0, new Intent(action), 0, UserHandle.CURRENT);
+ }
+
+ private static Intent settings(String action) {
+ return new Intent(action).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+ | Intent.FLAG_ACTIVITY_NO_HISTORY
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ }
+
+ @Override
+ public boolean isInvalidChargerWarningShowing() {
+ return mInvalidCharger;
+ }
+
+ @Override
+ public void updateLowBatteryWarning() {
+ updateNotification();
+ mFallbackDialogs.updateLowBatteryWarning();
+ }
+
+ @Override
+ public void dismissLowBatteryWarning() {
+ if (DEBUG) Slog.d(TAG, "dismissing low battery warning: level=" + mBatteryLevel);
+ dismissLowBatteryNotification();
+ mFallbackDialogs.dismissLowBatteryWarning();
+ }
+
+ private void dismissLowBatteryNotification() {
+ if (mWarning) Slog.i(TAG, "dismissing low battery notification");
+ mWarning = false;
+ updateNotification();
+ }
+
+ private boolean hasBatterySettings() {
+ return mOpenBatterySettings.resolveActivity(mContext.getPackageManager()) != null;
+ }
+
+ private boolean hasSaverSettings() {
+ return mOpenSaverSettings.resolveActivity(mContext.getPackageManager()) != null;
+ }
+
+ @Override
+ public void showLowBatteryWarning(boolean playSound) {
+ Slog.i(TAG,
+ "show low battery warning: level=" + mBatteryLevel
+ + " [" + mBucket + "]");
+ mPlaySound = playSound;
+ mWarning = true;
+ updateNotification();
+ mHandler.removeCallbacks(mDismissLowBatteryNotification);
+ mHandler.postDelayed(mDismissLowBatteryNotification, AUTO_DISMISS_MS);
+ }
+
+ private void attachLowBatterySound(Notification.Builder b) {
+ final ContentResolver cr = mContext.getContentResolver();
+
+ final int silenceAfter = Settings.Global.getInt(cr,
+ Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0);
+ final long offTime = SystemClock.elapsedRealtime() - mScreenOffTime;
+ if (silenceAfter > 0
+ && mScreenOffTime > 0
+ && offTime > silenceAfter) {
+ Slog.i(TAG, "screen off too long (" + offTime + "ms, limit " + silenceAfter
+ + "ms): not waking up the user with low battery sound");
+ return;
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "playing low battery sound. pick-a-doop!"); // WOMP-WOMP is deprecated
+ }
+
+ if (Settings.Global.getInt(cr, Settings.Global.POWER_SOUNDS_ENABLED, 1) == 1) {
+ final String soundPath = Settings.Global.getString(cr,
+ Settings.Global.LOW_BATTERY_SOUND);
+ if (soundPath != null) {
+ final Uri soundUri = Uri.parse("file://" + soundPath);
+ if (soundUri != null) {
+ b.setSound(soundUri, AudioManager.STREAM_SYSTEM);
+ Slog.d(TAG, "playing sound " + soundUri);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void dismissInvalidChargerWarning() {
+ dismissInvalidChargerNotification();
+ mFallbackDialogs.dismissInvalidChargerWarning();
+ }
+
+ private void dismissInvalidChargerNotification() {
+ if (mInvalidCharger) Slog.i(TAG, "dismissing invalid charger notification");
+ mInvalidCharger = false;
+ updateNotification();
+ }
+
+ @Override
+ public void showInvalidChargerWarning() {
+ mInvalidCharger = true;
+ updateNotification();
+ }
+
+ private void showStartSaverConfirmation() {
+ final AlertDialog d = new AlertDialog.Builder(mLightContext)
+ .setTitle(R.string.battery_saver_confirmation_title)
+ .setMessage(R.string.battery_saver_confirmation_text)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(R.string.battery_saver_confirmation_ok, mStartSaverMode)
+ .create();
+
+ d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+ d.getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ d.show();
+ }
+
+ private void setSaverSetting(boolean mode) {
+ final int val = mode ? 1 : 0;
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.LOW_POWER_MODE, val);
+ }
+
+ private final class Receiver extends BroadcastReceiver {
+
+ public void init() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_SHOW_FALLBACK_WARNING);
+ filter.addAction(ACTION_SHOW_FALLBACK_CHARGER);
+ filter.addAction(ACTION_SHOW_BATTERY_SETTINGS);
+ filter.addAction(ACTION_START_SAVER);
+ mContext.registerReceiver(this, filter, null, mHandler);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ Slog.i(TAG, "Received " + action);
+ if (action.equals(ACTION_SHOW_FALLBACK_WARNING)) {
+ dismissLowBatteryNotification();
+ mFallbackDialogs.showLowBatteryWarning(false /*playSound*/);
+ } else if (action.equals(ACTION_SHOW_FALLBACK_CHARGER)) {
+ dismissInvalidChargerNotification();
+ mFallbackDialogs.showInvalidChargerWarning();
+ } else if (action.equals(ACTION_SHOW_BATTERY_SETTINGS)) {
+ dismissLowBatteryNotification();
+ mContext.startActivityAsUser(mOpenBatterySettings, UserHandle.CURRENT);
+ } else if (action.equals(ACTION_START_SAVER)) {
+ dismissLowBatteryNotification();
+ showStartSaverConfirmation();
+ }
+ }
+ }
+
+ private final OnClickListener mStartSaverMode = new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ setSaverSetting(true);
+ }
+ });
+ }
+ };
+
+ private final Runnable mDismissLowBatteryNotification = new Runnable() {
+ @Override
+ public void run() {
+ dismissLowBatteryNotification();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 0fb0f8b..1bb7edb 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -17,13 +17,17 @@
package com.android.systemui.power;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
@@ -35,13 +39,15 @@
public class PowerUI extends SystemUI {
static final String TAG = "PowerUI";
-
static final boolean DEBUG = false;
- private WarningsUI mWarnings;
private final Handler mHandler = new Handler();
+ private final SettingsObserver mObserver = new SettingsObserver(mHandler);
+ private final Receiver mReceiver = new Receiver();
+ private PowerManager mPowerManager;
+ private WarningsUI mWarnings;
private int mBatteryLevel = 100;
private int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
private int mPlugType = 0;
@@ -53,24 +59,54 @@
private long mScreenOffTime = -1;
public void start() {
+ mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
+ mWarnings = new PowerNotificationWarnings(mContext);
- mLowBatteryAlertCloseLevel = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);
- mLowBatteryReminderLevels[0] = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_lowBatteryWarningLevel);
- mLowBatteryReminderLevels[1] = mContext.getResources().getInteger(
+ ContentObserver obs = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateBatteryWarningLevels();
+ }
+ };
+ final ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
+ false, obs, UserHandle.USER_ALL);
+ updateBatteryWarningLevels();
+ mReceiver.init();
+ mObserver.init();
+ }
+
+ private void setSaverMode(boolean mode) {
+ mWarnings.showSaverMode(mode);
+ }
+
+ private void setSaverTrigger(int level) {
+ mWarnings.setSaverTrigger(level);
+ }
+
+ void updateBatteryWarningLevels() {
+ int critLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_criticalBatteryWarningLevel);
- final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- mScreenOffTime = pm.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
- mWarnings = new PowerDialogWarnings(mContext);
+ final ContentResolver resolver = mContext.getContentResolver();
+ int defWarnLevel = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_lowBatteryWarningLevel);
+ int warnLevel = Settings.Global.getInt(resolver,
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
+ if (warnLevel == 0) {
+ warnLevel = defWarnLevel;
+ }
+ if (warnLevel < critLevel) {
+ warnLevel = critLevel;
+ }
- // Register for Intent broadcasts for...
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_BATTERY_CHANGED);
- filter.addAction(Intent.ACTION_SCREEN_OFF);
- filter.addAction(Intent.ACTION_SCREEN_ON);
- mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
+ mLowBatteryReminderLevels[0] = warnLevel;
+ mLowBatteryReminderLevels[1] = critLevel;
+ mLowBatteryAlertCloseLevel = mLowBatteryReminderLevels[0]
+ + mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
}
/**
@@ -87,7 +123,7 @@
if (level >= mLowBatteryAlertCloseLevel) {
return 1;
}
- if (level >= mLowBatteryReminderLevels[0]) {
+ if (level > mLowBatteryReminderLevels[0]) {
return 0;
}
final int N = mLowBatteryReminderLevels.length;
@@ -99,7 +135,23 @@
throw new RuntimeException("not possible!");
}
- private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ private final class Receiver extends BroadcastReceiver {
+
+ public void init() {
+ // Register for Intent broadcasts for...
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(Intent.ACTION_SCREEN_ON);
+ filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ mContext.registerReceiver(this, filter, null, mHandler);
+ updateSaverMode();
+ }
+
+ private void updateSaverMode() {
+ setSaverMode(mPowerManager.isPowerSaveMode());
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -160,6 +212,8 @@
mScreenOffTime = SystemClock.elapsedRealtime();
} else if (Intent.ACTION_SCREEN_ON.equals(action)) {
mScreenOffTime = -1;
+ } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
+ updateSaverMode();
} else {
Slog.w(TAG, "unknown intent: " + intent);
}
@@ -197,6 +251,8 @@
public interface WarningsUI {
void update(int batteryLevel, int bucket, long screenOffTime);
+ void setSaverTrigger(int level);
+ void showSaverMode(boolean mode);
void dismissLowBatteryWarning();
void showLowBatteryWarning(boolean playSound);
void dismissInvalidChargerWarning();
@@ -205,5 +261,29 @@
boolean isInvalidChargerWarningShowing();
void dump(PrintWriter pw);
}
+
+ private final class SettingsObserver extends ContentObserver {
+ private final Uri LOW_POWER_MODE_TRIGGER_LEVEL_URI =
+ Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL);
+
+ public SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ public void init() {
+ onChange(true, LOW_POWER_MODE_TRIGGER_LEVEL_URI);
+ final ContentResolver cr = mContext.getContentResolver();
+ cr.registerContentObserver(LOW_POWER_MODE_TRIGGER_LEVEL_URI, false, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (LOW_POWER_MODE_TRIGGER_LEVEL_URI.equals(uri)) {
+ final int level = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+ setSaverTrigger(level);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index c76ee8c..786cd9e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -287,6 +287,7 @@
public boolean activityIn;
public boolean activityOut;
public int overlayIconId;
+ public boolean filter;
@Override
public boolean copyTo(State other) {
@@ -300,6 +301,7 @@
o.activityIn = activityIn;
o.activityOut = activityOut;
o.overlayIconId = overlayIconId;
+ o.filter = filter;
return super.copyTo(other) || changed;
}
@@ -311,6 +313,7 @@
rt.insert(rt.length() - 1, ",activityIn=" + activityIn);
rt.insert(rt.length() - 1, ",activityOut=" + activityOut);
rt.insert(rt.length() - 1, ",overlayIconId=" + overlayIconId);
+ rt.insert(rt.length() - 1, ",filter=" + filter);
return rt;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
index 901cc10..d5fe033 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -93,12 +93,12 @@
final SignalState s = (SignalState) state;
mSignal.setImageDrawable(null); // force refresh
mSignal.setImageResource(s.iconId);
- mSignal.setColorFilter(FILTER);
+ mSignal.setColorFilter(s.filter ? FILTER : null);
if (s.overlayIconId > 0) {
mOverlay.setVisibility(VISIBLE);
mOverlay.setImageDrawable(null); // force refresh
mOverlay.setImageResource(s.overlayIconId);
- mOverlay.setColorFilter(FILTER);
+ mOverlay.setColorFilter(s.filter ? FILTER : null);
} else {
mOverlay.setVisibility(GONE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 182a0ce..6d91d33 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -72,12 +72,15 @@
if (cb == null) return;
final Resources r = mContext.getResources();
- state.iconId = cb.enabled && (cb.mobileSignalIconId > 0)
+ state.iconId = cb.noSim
+ ? R.drawable.stat_sys_no_sim
+ : cb.enabled && (cb.mobileSignalIconId > 0)
? cb.mobileSignalIconId
: R.drawable.ic_qs_signal_no_signal;
state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiEnabled
? cb.dataTypeIconId
: 0;
+ state.filter = state.iconId != R.drawable.stat_sys_no_sim;
state.activityIn = cb.enabled && cb.activityIn;
state.activityOut = cb.enabled && cb.activityOut;
@@ -117,6 +120,7 @@
boolean activityIn;
boolean activityOut;
String enabledDesc;
+ boolean noSim;
}
private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
@@ -134,7 +138,7 @@
int mobileSignalIconId,
String mobileSignalContentDescriptionId, int dataTypeIconId,
boolean activityIn, boolean activityOut,
- String dataTypeContentDescriptionId, String description) {
+ String dataTypeContentDescriptionId, String description, boolean noSim) {
final CallbackInfo info = new CallbackInfo(); // TODO pool?
info.enabled = enabled;
info.wifiEnabled = mWifiEnabled;
@@ -145,6 +149,7 @@
info.activityIn = activityIn;
info.activityOut = activityOut;
info.enabledDesc = description;
+ info.noSim = noSim;
refreshState(info);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 5301362..7c2c7c3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -71,6 +71,6 @@
state.visible = mVisible;
state.value = enabled;
state.label = mContext.getString(R.string.quick_settings_inversion_label);
- state.iconId = R.drawable.ic_qs_color_inversion;
+ state.iconId = enabled ? R.drawable.ic_qs_inversion_on : R.drawable.ic_qs_inversion_off;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index db9b054..04f1eb5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -16,9 +16,6 @@
package com.android.systemui.qs.tiles;
-import android.content.res.Resources;
-import android.graphics.drawable.AnimationDrawable;
-
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.LocationController;
@@ -63,28 +60,15 @@
protected void handleUpdateState(BooleanState state, Object arg) {
final boolean locationEnabled = mController.isLocationEnabled();
state.visible = true;
- if (state.value != locationEnabled) {
- state.value = locationEnabled;
- final Resources res = mContext.getResources();
- final AnimationDrawable d = (AnimationDrawable) res.getDrawable(locationEnabled
- ? R.drawable.ic_qs_location_on
- : R.drawable.ic_qs_location_off);
- state.icon = d;
- mUiHandler.post(new Runnable() {
- @Override
- public void run() {
- d.start();
- }
- });
- }
+ state.value = locationEnabled;
if (locationEnabled) {
- if (state.icon == null) state.iconId = R.drawable.ic_qs_location_01;
+ state.iconId = R.drawable.ic_qs_location_on;
state.label = mContext.getString(R.string.quick_settings_location_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_location,
mContext.getString(R.string.accessibility_desc_on));
} else {
- if (state.icon == null) state.iconId = R.drawable.ic_qs_location_11;
+ state.iconId = R.drawable.ic_qs_location_off;
state.label = mContext.getString(R.string.quick_settings_location_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_location,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
index b981ed6..c4bdb19 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
@@ -69,6 +69,7 @@
@Override
public void onViewAttachedToWindow(View v) {
+ vp.updateStates();
volumeComponent.setVolumePanel(vp);
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 6b73002..a236497 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -87,6 +87,7 @@
state.connected = wifiConnected;
state.activityIn = cb.enabled && cb.activityIn;
state.activityOut = cb.enabled && cb.activityOut;
+ state.filter = true;
final String signalContentDescription;
final Resources r = mContext.getResources();
if (wifiConnected) {
@@ -159,7 +160,7 @@
int mobileSignalIconId,
String mobileSignalContentDescriptionId, int dataTypeIconId,
boolean activityIn, boolean activityOut,
- String dataTypeContentDescriptionId, String description) {
+ String dataTypeContentDescriptionId, String description, boolean noSim) {
// noop
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
index 116d755d..e03c01c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
@@ -273,6 +273,13 @@
}
}
+ @Override
+ public void setCallback(Callbacks cb) {
+ if (mUseAlternateRecents) {
+ mAlternateRecents.setRecentsComponentCallback(cb);
+ }
+ }
+
/**
* Send broadcast only if BOOT_COMPLETED
*/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 2f6d58f..8dcdcdb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -27,7 +27,6 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
@@ -35,16 +34,13 @@
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.UserHandle;
-import android.util.DisplayMetrics;
-import android.view.Display;
-import android.view.Surface;
-import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
import com.android.systemui.R;
+import com.android.systemui.RecentsComponent;
+import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -129,8 +125,10 @@
final public static int MSG_TOGGLE_RECENTS = 6;
final public static int MSG_START_ENTER_ANIMATION = 7;
- final public static String EXTRA_ANIMATING_WITH_THUMBNAIL = "recents.animatingWithThumbnail";
- final public static String EXTRA_FROM_ALT_TAB = "recents.triggeredFromAltTab";
+ final public static String EXTRA_FROM_HOME = "recents.triggeredOverHome";
+ final public static String EXTRA_FROM_APP_THUMBNAIL = "recents.animatingWithThumbnail";
+ final public static String EXTRA_FROM_APP_FULL_SCREENSHOT = "recents.thumbnail";
+ final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "recents.triggeredFromAltTab";
final public static String KEY_CONFIGURATION_DATA = "recents.data.updateForConfiguration";
final public static String KEY_WINDOW_RECT = "recents.windowRect";
final public static String KEY_SYSTEM_INSETS = "recents.systemInsets";
@@ -138,7 +136,6 @@
final public static String KEY_TWO_TASK_STACK_RECT = "recents.twoCountTaskRect";
final public static String KEY_MULTIPLE_TASK_STACK_RECT = "recents.multipleCountTaskRect";
-
final static int sMinToggleDelay = 425;
final static String sToggleRecentsAction = "com.android.systemui.recents.SHOW_RECENTS";
@@ -146,6 +143,9 @@
final static String sRecentsActivity = "com.android.systemui.recents.RecentsActivity";
final static String sRecentsService = "com.android.systemui.recents.RecentsService";
+ static Bitmap sLastScreenshot;
+ static RecentsComponent.Callbacks sRecentsComponentCallbacks;
+
Context mContext;
SystemServicesProxy mSystemServicesProxy;
@@ -213,15 +213,19 @@
if (Console.Enabled) {
Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|hideRecents]");
}
+
if (mServiceIsBound && mBootCompleted) {
- // Notify recents to close it
- try {
- Bundle data = new Bundle();
- Message msg = Message.obtain(null, MSG_HIDE_RECENTS, triggeredFromAltTab ? 1 : 0, 0);
- msg.setData(data);
- mService.send(msg);
- } catch (RemoteException re) {
- re.printStackTrace();
+ if (isRecentsTopMost(null)) {
+ // Notify recents to close it
+ try {
+ Bundle data = new Bundle();
+ Message msg = Message.obtain(null, MSG_HIDE_RECENTS,
+ triggeredFromAltTab ? 1 : 0, 0);
+ msg.setData(data);
+ mService.send(msg);
+ } catch (RemoteException re) {
+ re.printStackTrace();
+ }
}
}
}
@@ -283,7 +287,7 @@
/** Updates each of the task animation rects. */
void updateAnimationRects() {
- if (mServiceIsBound && mBootCompleted) {
+ if (mServiceIsBound) {
Resources res = mContext.getResources();
int statusBarHeight = res.getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
@@ -343,80 +347,6 @@
}
}
- /** Converts from the device rotation to the degree */
- float getDegreesForRotation(int value) {
- switch (value) {
- case Surface.ROTATION_90:
- return 360f - 90f;
- case Surface.ROTATION_180:
- return 360f - 180f;
- case Surface.ROTATION_270:
- return 360f - 270f;
- }
- return 0f;
- }
-
- /** Takes a screenshot of the surface */
- Bitmap takeScreenshot(Display display) {
- DisplayMetrics dm = new DisplayMetrics();
- display.getRealMetrics(dm);
- float[] dims = {dm.widthPixels, dm.heightPixels};
- float degrees = getDegreesForRotation(display.getRotation());
- boolean requiresRotation = (degrees > 0);
- if (requiresRotation) {
- // Get the dimensions of the device in its native orientation
- Matrix m = new Matrix();
- m.preRotate(-degrees);
- m.mapPoints(dims);
- dims[0] = Math.abs(dims[0]);
- dims[1] = Math.abs(dims[1]);
- }
- return SurfaceControl.screenshot((int) dims[0], (int) dims[1]);
- }
-
- /** Creates the activity options for a thumbnail transition. */
- ActivityOptions getThumbnailTransitionActivityOptions(Rect taskRect) {
- // Loading from thumbnail
- Bitmap thumbnail;
- Bitmap firstThumbnail = loadFirstTaskThumbnail();
- if (firstThumbnail != null) {
- // Create the thumbnail
- thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
- Bitmap.Config.ARGB_8888);
- int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
- Canvas c = new Canvas(thumbnail);
- c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
- new Rect(0, 0, taskRect.width(), taskRect.height()), null);
- c.setBitmap(null);
- // Recycle the old thumbnail
- firstThumbnail.recycle();
- } else {
- // Load the thumbnail from the screenshot if can't get one from the system
- WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- Display display = wm.getDefaultDisplay();
- Bitmap screenshot = takeScreenshot(display);
- if (screenshot != null) {
- Resources res = mContext.getResources();
- int size = Math.min(screenshot.getWidth(), screenshot.getHeight());
- int statusBarHeight = res.getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_height);
- thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
- Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(thumbnail);
- c.drawBitmap(screenshot, new Rect(0, statusBarHeight, size, statusBarHeight +
- size), new Rect(0, 0, taskRect.width(), taskRect.height()), null);
- c.setBitmap(null);
- // Recycle the temporary screenshot
- screenshot.recycle();
- } else {
- return null;
- }
- }
-
- return ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView, thumbnail,
- taskRect.left, taskRect.top, this);
- }
-
/** Returns whether the recents is currently running */
boolean isRecentsTopMost(AtomicBoolean isHomeTopMost) {
SystemServicesProxy ssp = mSystemServicesProxy;
@@ -462,10 +392,12 @@
mService.send(msg);
// Time this path
- Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
- Constants.Log.App.TimeRecentsStartupKey, "sendToggleRecents");
- Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
- Constants.Log.App.TimeRecentsLaunchKey, "sendToggleRecents");
+ if (Console.Enabled) {
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "sendToggleRecents");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey, "sendToggleRecents");
+ }
} catch (RemoteException re) {
re.printStackTrace();
}
@@ -486,6 +418,68 @@
}
}
+ /**
+ * Creates the activity options for a unknown state->recents transition.
+ */
+ ActivityOptions getUnknownTransitionActivityOptions() {
+ // Reset the last screenshot
+ consumeLastScreenshot();
+ return ActivityOptions.makeCustomAnimation(mContext,
+ R.anim.recents_from_unknown_enter,
+ R.anim.recents_from_unknown_exit, mHandler, this);
+ }
+
+ /**
+ * Creates the activity options for a home->recents transition.
+ */
+ ActivityOptions getHomeTransitionActivityOptions() {
+ // Reset the last screenshot
+ consumeLastScreenshot();
+ return ActivityOptions.makeCustomAnimation(mContext,
+ R.anim.recents_from_launcher_enter,
+ R.anim.recents_from_launcher_exit, mHandler, this);
+ }
+
+ /**
+ * Creates the activity options for an app->recents transition. If this method sets the static
+ * screenshot, then we will use that for the transition.
+ */
+ ActivityOptions getThumbnailTransitionActivityOptions(Rect taskRect) {
+ // Recycle the last screenshot
+ consumeLastScreenshot();
+
+ // Take the full screenshot
+ if (Constants.DebugFlags.App.EnableScreenshotAppTransition) {
+ sLastScreenshot = mSystemServicesProxy.takeScreenshot();
+ if (sLastScreenshot != null) {
+ return ActivityOptions.makeCustomAnimation(mContext,
+ R.anim.recents_from_app_enter,
+ R.anim.recents_from_app_exit, mHandler, this);
+ }
+ }
+
+ // If the screenshot fails, then load the first task thumbnail and use that
+ Bitmap firstThumbnail = loadFirstTaskThumbnail();
+ if (firstThumbnail != null) {
+ // Create the new thumbnail for the animation down
+ // XXX: We should find a way to optimize this so we don't need to create a new bitmap
+ Bitmap thumbnail = Bitmap.createBitmap(taskRect.width(), taskRect.height(),
+ Bitmap.Config.ARGB_8888);
+ int size = Math.min(firstThumbnail.getWidth(), firstThumbnail.getHeight());
+ Canvas c = new Canvas(thumbnail);
+ c.drawBitmap(firstThumbnail, new Rect(0, 0, size, size),
+ new Rect(0, 0, taskRect.width(), taskRect.height()), null);
+ c.setBitmap(null);
+ // Recycle the old thumbnail
+ firstThumbnail.recycle();
+ return ActivityOptions.makeThumbnailScaleDownAnimation(mStatusBarView,
+ thumbnail, taskRect.left, taskRect.top, this);
+ }
+
+ // If both the screenshot and thumbnail fails, then just fall back to the default transition
+ return getUnknownTransitionActivityOptions();
+ }
+
/** Starts the recents activity */
void startRecentsActivity(boolean isTopTaskHome) {
// If Recents is not the front-most activity and we should animate into it. If
@@ -498,39 +492,52 @@
Rect taskRect = getAnimationTaskRect(recentTasks);
boolean useThumbnailTransition = !isTopTaskHome &&
hasValidTaskRects();
+ boolean hasRecentTasks = !recentTasks.isEmpty();
if (useThumbnailTransition) {
// Try starting with a thumbnail transition
ActivityOptions opts = getThumbnailTransitionActivityOptions(taskRect);
if (opts != null) {
- startAlternateRecentsActivity(opts, true);
+ if (sLastScreenshot != null) {
+ startAlternateRecentsActivity(opts, EXTRA_FROM_APP_FULL_SCREENSHOT);
+ } else {
+ startAlternateRecentsActivity(opts, EXTRA_FROM_APP_THUMBNAIL);
+ }
} else {
// Fall through below to the non-thumbnail transition
useThumbnailTransition = false;
}
+ } else {
+ // If there is no thumbnail transition, but is launching from home into recents, then
+ // use a quick home transition and do the animation from home
+ if (hasRecentTasks && Constants.DebugFlags.App.EnableHomeTransition) {
+ ActivityOptions opts = getHomeTransitionActivityOptions();
+ startAlternateRecentsActivity(opts, EXTRA_FROM_HOME);
+ } else {
+ // Otherwise we do the normal fade from an unknown source
+ ActivityOptions opts = getUnknownTransitionActivityOptions();
+ startAlternateRecentsActivity(opts, null);
+ }
}
- // If there is no thumbnail transition, then just use a generic transition
- if (!useThumbnailTransition) {
- ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
- R.anim.recents_from_launcher_enter,
- R.anim.recents_from_launcher_exit, mHandler, this);
- startAlternateRecentsActivity(opts, false);
+ if (Console.Enabled) {
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "startRecentsActivity");
}
-
- Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
- Constants.Log.App.TimeRecentsStartupKey, "startRecentsActivity");
mLastToggleTime = System.currentTimeMillis();
}
/** Starts the recents activity */
- void startAlternateRecentsActivity(ActivityOptions opts, boolean animatingWithThumbnail) {
+ void startAlternateRecentsActivity(ActivityOptions opts, String extraFlag) {
Intent intent = new Intent(sToggleRecentsAction);
intent.setClassName(sRecentsPackage, sRecentsActivity);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- intent.putExtra(EXTRA_ANIMATING_WITH_THUMBNAIL, animatingWithThumbnail);
- intent.putExtra(EXTRA_FROM_ALT_TAB, mTriggeredFromAltTab);
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+ | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+ if (extraFlag != null) {
+ intent.putExtra(extraFlag, true);
+ }
+ intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, mTriggeredFromAltTab);
if (opts != null) {
mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
UserHandle.USER_CURRENT));
@@ -539,6 +546,30 @@
}
}
+ /** Returns the last screenshot taken, this will be called by the RecentsActivity. */
+ public static Bitmap getLastScreenshot() {
+ return sLastScreenshot;
+ }
+
+ /** Recycles the last screenshot taken, this will be called by the RecentsActivity. */
+ public static void consumeLastScreenshot() {
+ if (sLastScreenshot != null) {
+ sLastScreenshot.recycle();
+ sLastScreenshot = null;
+ }
+ }
+
+ /** Sets the RecentsComponent callbacks. */
+ public void setRecentsComponentCallback(RecentsComponent.Callbacks cb) {
+ sRecentsComponentCallbacks = cb;
+ }
+
+ /** Notifies the callbacks that the visibility of Recents has changed. */
+ public static void notifyVisibilityChanged(boolean visible) {
+ if (sRecentsComponentCallbacks != null) {
+ sRecentsComponentCallbacks.onVisibilityChanged(visible);
+ }
+ }
/**** OnAnimationStartedListener Implementation ****/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 76e88a5..1d355cd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -25,6 +25,10 @@
public static final boolean Verbose = false;
public static class App {
+ // Enables the home->Recents transition
+ public static final boolean EnableHomeTransition = true;
+ // Enables the screenshot app->Recents transition
+ public static final boolean EnableScreenshotAppTransition = false;
// Enables the filtering of tasks according to their grouping
public static final boolean EnableTaskFiltering = false;
// Enables clipping of tasks against each other
@@ -52,8 +56,11 @@
public static class App {
public static final String TimeRecentsStartupKey = "startup";
public static final String TimeRecentsLaunchKey = "launchTask";
- public static final boolean TimeRecentsStartup = false;
- public static final boolean TimeRecentsLaunchTask = false;
+ public static final String TimeRecentsScreenshotTransitionKey = "screenshot";
+ public static final boolean TimeRecentsStartup = true;
+ public static final boolean TimeRecentsLaunchTask = true;
+ public static final boolean TimeRecentsScreenshotTransition = true;
+
public static final boolean RecentsComponent = false;
public static final boolean TaskDataLoader = false;
@@ -106,7 +113,7 @@
// The height of the peek space relative to the stack height
public static final float StackPeekHeightPct = 0.1f;
// The min scale of the last card in the peek area
- public static final float StackPeekMinScale = 0.9f;
+ public static final float StackPeekMinScale = 0.8f;
// The number of cards we see in the peek space
public static final int StackPeekNumCards = 3;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/DozeTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/DozeTrigger.java
new file mode 100644
index 0000000..247aa6f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/DozeTrigger.java
@@ -0,0 +1,72 @@
+/*
+ * 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.systemui.recents;
+
+import android.os.Handler;
+
+/**
+ * A dozer is a class that fires a trigger after it falls asleep. You can occasionally poke it to
+ * wake it up, but it will fall asleep if left untouched.
+ */
+public class DozeTrigger {
+
+ Handler mHandler;
+
+ boolean mIsDozing;
+ boolean mHasTriggered;
+ int mDozeDurationSeconds;
+ Runnable mSleepRunnable;
+
+ // Sleep-runnable
+ Runnable mDozeRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mSleepRunnable.run();
+ mIsDozing = false;
+ mHasTriggered = true;
+ }
+ };
+
+ public DozeTrigger(int dozeDurationSeconds, Runnable sleepRunnable) {
+ mHandler = new Handler();
+ mDozeDurationSeconds = dozeDurationSeconds;
+ mSleepRunnable = sleepRunnable;
+ }
+
+ /** Starts dozing. This also resets the trigger flag. */
+ public void startDozing() {
+ poke();
+ mHasTriggered = false;
+ }
+
+ /** Poke this dozer to wake it up for a little bit. */
+ public void poke() {
+ mHandler.removeCallbacks(mDozeRunnable);
+ mHandler.postDelayed(mDozeRunnable, mDozeDurationSeconds * 1000);
+ mIsDozing = true;
+ }
+
+ /** Returns whether we are dozing or not. */
+ public boolean isDozing() {
+ return mIsDozing;
+ }
+
+ /** Returns whether the trigger has fired at least once. */
+ public boolean hasTriggered() {
+ return mHasTriggered;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 8680786..dce8f57 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -22,11 +22,9 @@
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Pair;
import android.view.Gravity;
@@ -34,15 +32,17 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.WindowManager;
import android.widget.FrameLayout;
import com.android.systemui.R;
import com.android.systemui.recents.model.SpaceNode;
import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.FullScreenTransitionView;
import com.android.systemui.recents.views.RecentsView;
+import com.android.systemui.recents.views.ViewAnimation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.Set;
/** Our special app widget host */
class RecentsAppWidgetHost extends AppWidgetHost {
@@ -66,11 +66,16 @@
/* Activity */
public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks,
- RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks {
+ RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks,
+ FullScreenTransitionView.FullScreenTransitionViewCallbacks {
+
FrameLayout mContainerView;
RecentsView mRecentsView;
View mEmptyView;
View mNavBarScrimView;
+ FullScreenTransitionView mFullScreenshotView;
+
+ RecentsConfiguration mConfig;
AppWidgetHost mAppWidgetHost;
AppWidgetProviderInfo mSearchAppWidgetInfo;
@@ -79,6 +84,19 @@
boolean mVisible;
boolean mTaskLaunched;
+ private static Method sPropertyMethod;
+ static {
+ try {
+ Class<?> c = Class.forName("android.view.GLES20Canvas");
+ sPropertyMethod = c.getDeclaredMethod("setProperty", String.class, String.class);
+ if (!sPropertyMethod.isAccessible()) sPropertyMethod.setAccessible(true);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ }
+ }
+
// Broadcast receiver to handle messages from our RecentsService
BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -93,8 +111,15 @@
// Dismiss recents, launching the focused task
dismissRecentsIfVisible();
} else {
- // Otherwise, just finish the activity without launching any other activities
- finish();
+ // If we are mid-animation into Recents, then reverse it and finish
+ if (mFullScreenshotView == null ||
+ !mFullScreenshotView.cancelAnimateOnEnterRecents(mFinishRunnable)) {
+ // Otherwise, just finish the activity without launching any other activities
+ ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(context,
+ null, mFinishRunnable, null);
+ mRecentsView.startExitToHomeAnimation(
+ new ViewAnimation.TaskViewExitContext(exitTrigger));
+ }
}
} else if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
// Try and unfilter and filtered stacks
@@ -104,7 +129,9 @@
}
} else if (action.equals(RecentsService.ACTION_START_ENTER_ANIMATION)) {
// Try and start the enter animation (or restart it on configuration changed)
- mRecentsView.startOnEnterAnimation();
+ mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(mFullScreenshotView));
+ // Call our callback
+ onEnterAnimationTriggered();
}
}
};
@@ -113,19 +140,28 @@
BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ // Mark recents as no longer visible
+ AlternateRecentsComponent.notifyVisibilityChanged(false);
+ // Finish without an animations
finish();
}
};
+ // A runnable to finish the Recents activity
+ Runnable mFinishRunnable = new Runnable() {
+ @Override
+ public void run() {
+ // Mark recents as no longer visible
+ AlternateRecentsComponent.notifyVisibilityChanged(false);
+ // Finish with an animations
+ finish();
+ overridePendingTransition(R.anim.recents_to_launcher_enter,
+ R.anim.recents_to_launcher_exit);
+ }
+ };
+
/** Updates the set of recent tasks */
void updateRecentsTasks(Intent launchIntent) {
- // Update the configuration based on the launch intent
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- config.launchedWithThumbnailAnimation = launchIntent.getBooleanExtra(
- AlternateRecentsComponent.EXTRA_ANIMATING_WITH_THUMBNAIL, false);
- config.launchedFromAltTab = launchIntent.getBooleanExtra(
- AlternateRecentsComponent.EXTRA_FROM_ALT_TAB, false);
-
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
SpaceNode root = loader.reload(this, Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount);
ArrayList<TaskStack> stacks = root.getStacks();
@@ -133,33 +169,37 @@
mRecentsView.setBSP(root);
}
- // Hide the scrim by default when we enter recents
- mNavBarScrimView.setVisibility(View.INVISIBLE);
+ // Update the configuration based on the launch intent
+ mConfig.launchedFromHome = launchIntent.getBooleanExtra(
+ AlternateRecentsComponent.EXTRA_FROM_HOME, false);
+ mConfig.launchedFromAppWithThumbnail = launchIntent.getBooleanExtra(
+ AlternateRecentsComponent.EXTRA_FROM_APP_THUMBNAIL, false);
+ mConfig.launchedFromAppWithScreenshot = launchIntent.getBooleanExtra(
+ AlternateRecentsComponent.EXTRA_FROM_APP_FULL_SCREENSHOT, false);
+ mConfig.launchedWithAltTab = launchIntent.getBooleanExtra(
+ AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
+ mConfig.launchedWithNoRecentTasks = !root.hasTasks();
+
+ if (mConfig.shouldAnimateNavBarScrim()) {
+ // Hide the scrim if we animate into Recents with window transitions
+ mNavBarScrimView.setVisibility(View.INVISIBLE);
+ } else {
+ // Show the scrim if we animate into Recents without window transitions
+ mNavBarScrimView.setVisibility(View.VISIBLE);
+ }
// Add the default no-recents layout
- if (stacks.size() == 1 && stacks.get(0).getTaskCount() == 0) {
+ if (mConfig.launchedWithNoRecentTasks) {
mEmptyView.setVisibility(View.VISIBLE);
-
- // Dim the background even more
- WindowManager.LayoutParams wlp = getWindow().getAttributes();
- wlp.dimAmount = Constants.Values.Window.DarkBackgroundDim;
- getWindow().setAttributes(wlp);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+ mEmptyView.setBackgroundColor(0x80000000);
} else {
mEmptyView.setVisibility(View.GONE);
-
- // Un-dim the background
- WindowManager.LayoutParams wlp = getWindow().getAttributes();
- wlp.dimAmount = 0f;
- getWindow().setAttributes(wlp);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
}
}
/** Attempts to allocate and bind the search bar app widget */
void bindSearchBarAppWidget() {
if (Constants.DebugFlags.App.EnableSearchLayout) {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
// Reset the host view and widget info
@@ -167,7 +207,7 @@
mSearchAppWidgetInfo = null;
// Try and load the app widget id from the settings
- int appWidgetId = config.searchBarAppWidgetId;
+ int appWidgetId = mConfig.searchBarAppWidgetId;
if (appWidgetId >= 0) {
mSearchAppWidgetInfo = ssp.getAppWidgetInfo(appWidgetId);
if (mSearchAppWidgetInfo == null) {
@@ -197,7 +237,7 @@
}
// Save the app widget id into the settings
- config.updateSearchBarAppWidgetId(this, widgetInfo.first);
+ mConfig.updateSearchBarAppWidgetId(this, widgetInfo.first);
mSearchAppWidgetInfo = widgetInfo.second;
}
}
@@ -207,8 +247,7 @@
/** Creates the search bar app widget view */
void addSearchBarAppWidgetView() {
if (Constants.DebugFlags.App.EnableSearchLayout) {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- int appWidgetId = config.searchBarAppWidgetId;
+ int appWidgetId = mConfig.searchBarAppWidgetId;
if (appWidgetId >= 0) {
if (Console.Enabled) {
Console.log(Constants.Log.App.SystemUIHandshake,
@@ -234,9 +273,19 @@
/** Dismisses recents if we are already visible and the intent is to toggle the recents view */
boolean dismissRecentsIfVisible() {
if (mVisible) {
- if (!mRecentsView.launchFocusedTask()) {
- if (!mRecentsView.launchFirstTask()) {
- finish();
+ // If we are mid-animation into Recents, then reverse it and finish
+ if (mFullScreenshotView == null ||
+ !mFullScreenshotView.cancelAnimateOnEnterRecents(mFinishRunnable)) {
+ // If we have a focused task, then launch that task
+ if (!mRecentsView.launchFocusedTask()) {
+ // If there are any tasks, then launch the first task
+ if (!mRecentsView.launchFirstTask()) {
+ // We really shouldn't hit this, but if we do, just animate out (aka. finish)
+ ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this,
+ null, mFinishRunnable, null);
+ mRecentsView.startExitToHomeAnimation(
+ new ViewAnimation.TaskViewExitContext(exitTrigger));
+ }
}
}
return true;
@@ -258,7 +307,7 @@
// Initialize the loader and the configuration
RecentsTaskLoader.initialize(this);
- RecentsConfiguration.reinitialize(this);
+ mConfig = RecentsConfiguration.reinitialize(this);
// Initialize the widget host (the host id is static and does not change)
mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId, this);
@@ -277,16 +326,32 @@
LayoutInflater inflater = LayoutInflater.from(this);
mEmptyView = inflater.inflate(R.layout.recents_empty, mContainerView, false);
mNavBarScrimView = inflater.inflate(R.layout.recents_nav_bar_scrim, mContainerView, false);
+ mNavBarScrimView.setLayoutParams(new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM));
+ if (Constants.DebugFlags.App.EnableScreenshotAppTransition) {
+ mFullScreenshotView = new FullScreenTransitionView(this, this);
+ mFullScreenshotView.setLayoutParams(new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+ }
mContainerView = new FrameLayout(this);
mContainerView.addView(mRecentsView);
mContainerView.addView(mEmptyView);
+ if (Constants.DebugFlags.App.EnableScreenshotAppTransition) {
+ mContainerView.addView(mFullScreenshotView);
+ }
mContainerView.addView(mNavBarScrimView);
setContentView(mContainerView);
// Update the recent tasks
updateRecentsTasks(getIntent());
+ // Prepare the screenshot transition if necessary
+ if (Constants.DebugFlags.App.EnableScreenshotAppTransition) {
+ mFullScreenshotView.prepareAnimateOnEnterRecents(AlternateRecentsComponent.getLastScreenshot());
+ }
+
// Bind the search app widget when we first start up
bindSearchBarAppWidget();
// Add the search bar layout
@@ -296,11 +361,23 @@
if (savedInstanceState != null) {
onConfigurationChange();
}
+
+ // XXX: Update the shadows
+ try {
+ sPropertyMethod.invoke(null, "ambientShadowStrength", String.valueOf(35f));
+ sPropertyMethod.invoke(null, "ambientRatio", String.valueOf(0.5f));
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ }
}
void onConfigurationChange() {
// Try and start the enter animation (or restart it on configuration changed)
- mRecentsView.startOnEnterAnimation();
+ mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(mFullScreenshotView));
+ // Call our callback
+ onEnterAnimationTriggered();
}
@Override
@@ -319,11 +396,16 @@
// Initialize the loader and the configuration
RecentsTaskLoader.initialize(this);
- RecentsConfiguration.reinitialize(this);
+ mConfig = RecentsConfiguration.reinitialize(this);
// Update the recent tasks
updateRecentsTasks(intent);
+ // Prepare the screenshot transition if necessary
+ if (Constants.DebugFlags.App.EnableScreenshotAppTransition) {
+ mFullScreenshotView.prepareAnimateOnEnterRecents(AlternateRecentsComponent.getLastScreenshot());
+ }
+
// Don't attempt to rebind the search bar widget, but just add the search bar layout
addSearchBarAppWidgetView();
}
@@ -337,8 +419,7 @@
super.onStart();
// Start listening for widget package changes if there is one bound
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- if (config.searchBarAppWidgetId >= 0) {
+ if (mConfig.searchBarAppWidgetId >= 0) {
mAppWidgetHost.startListening();
}
@@ -412,8 +493,7 @@
super.onStop();
// Stop listening for widget package changes if there was one bound
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- if (config.searchBarAppWidgetId >= 0) {
+ if (mConfig.searchBarAppWidgetId >= 0) {
mAppWidgetHost.stopListening();
}
@@ -451,55 +531,99 @@
}
@Override
+ public void onUserInteraction() {
+ mRecentsView.onUserInteraction();
+ }
+
+ @Override
public void onBackPressed() {
- // Unfilter any stacks
- if (!mRecentsView.unfilterFilteredStacks()) {
- if (!mRecentsView.launchFirstTask()) {
- super.onBackPressed();
+ // If we are mid-animation into Recents, then reverse it and finish
+ if (mFullScreenshotView == null ||
+ !mFullScreenshotView.cancelAnimateOnEnterRecents(mFinishRunnable)) {
+ // If we are currently filtering in any stacks, unfilter them first
+ if (!mRecentsView.unfilterFilteredStacks()) {
+ if (mConfig.launchedFromHome) {
+ // Just start the animation out of recents
+ ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this,
+ null, mFinishRunnable, null);
+ mRecentsView.startExitToHomeAnimation(
+ new ViewAnimation.TaskViewExitContext(exitTrigger));
+ } else {
+ // Otherwise, try and launch the first task
+ if (!mRecentsView.launchFirstTask()) {
+ // If there are no tasks, then just finish recents
+ ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this,
+ null, mFinishRunnable, null);
+ mRecentsView.startExitToHomeAnimation(
+ new ViewAnimation.TaskViewExitContext(exitTrigger));
+ }
+ }
}
}
}
- @Override
public void onEnterAnimationTriggered() {
// Fade in the scrim
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- if (config.hasNavBarScrim()) {
+ if (mConfig.shouldAnimateNavBarScrim() && mConfig.hasNavBarScrim()) {
mNavBarScrimView.setVisibility(View.VISIBLE);
- mNavBarScrimView.setAlpha(0f);
- mNavBarScrimView.animate().alpha(1f)
- .setStartDelay(config.taskBarEnterAnimDelay)
- .setDuration(config.navBarScrimEnterDuration)
- .setInterpolator(config.fastOutSlowInInterpolator)
- .withLayer()
+ mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
+ mNavBarScrimView.animate()
+ .translationY(0)
+ .setStartDelay(mConfig.taskBarEnterAnimDelay)
+ .setDuration(mConfig.navBarScrimEnterDuration)
+ .setInterpolator(mConfig.quintOutInterpolator)
.start();
}
}
@Override
+ public void onExitAnimationTriggered() {
+ // Fade out the scrim
+ if (mConfig.shouldAnimateNavBarScrim() && mConfig.hasNavBarScrim()) {
+ mNavBarScrimView.animate()
+ .translationY(mNavBarScrimView.getMeasuredHeight())
+ .setStartDelay(0)
+ .setDuration(mConfig.taskBarExitAnimDuration)
+ .setInterpolator(mConfig.fastOutSlowInInterpolator)
+ .start();
+ }
+ }
+
+ @Override
+ public void onEnterAnimationComplete(boolean canceled) {
+ if (!canceled) {
+ // Reset the full screenshot transition view
+ if (Constants.DebugFlags.App.EnableScreenshotAppTransition) {
+ mFullScreenshotView.reset();
+ }
+
+ // XXX: We should clean up the screenshot in this case as well, but it needs to happen
+ // after to animate up
+ }
+ // Recycle the full screen screenshot
+ AlternateRecentsComponent.consumeLastScreenshot();
+ }
+
+ @Override
public void onTaskLaunching(boolean isTaskInStackBounds) {
mTaskLaunched = true;
// Fade out the scrim
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- if (!isTaskInStackBounds && config.hasNavBarScrim()) {
- mNavBarScrimView.animate().alpha(0f)
- .setStartDelay(0)
- .setDuration(config.taskBarExitAnimDuration)
- .setInterpolator(config.fastOutSlowInInterpolator)
- .withLayer()
- .start();
+ if (!isTaskInStackBounds && mConfig.hasNavBarScrim()) {
+ onExitAnimationTriggered();
}
+
+ // Mark recents as no longer visible
+ AlternateRecentsComponent.notifyVisibilityChanged(false);
}
@Override
public void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
- if (appWidgetId > -1 && appWidgetId == config.searchBarAppWidgetId) {
+ if (appWidgetId > -1 && appWidgetId == mConfig.searchBarAppWidgetId) {
// The search provider may have changed, so just delete the old widget and bind it again
ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId);
- config.updateSearchBarAppWidgetId(this, -1);
+ mConfig.updateSearchBarAppWidgetId(this, -1);
// Load the widget again
bindSearchBarAppWidget();
addSearchBarAppWidgetView();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 0cf6ee6..c1a8ee6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -37,27 +37,40 @@
DisplayMetrics mDisplayMetrics;
- public Rect systemInsets = new Rect();
- public Rect displayRect = new Rect();
-
- boolean isLandscape;
- boolean transposeRecentsLayoutWithOrientation;
- int searchBarAppWidgetId = -1;
-
+ /** Animations */
public float animationPxMovementPerSecond;
+ /** Interpolators */
public Interpolator fastOutSlowInInterpolator;
public Interpolator fastOutLinearInInterpolator;
public Interpolator linearOutSlowInInterpolator;
+ public Interpolator quintOutInterpolator;
+ /** Filtering */
public int filteringCurrentViewsMinAnimDuration;
public int filteringNewViewsMinAnimDuration;
- public int taskStackScrollDismissInfoPaneDistance;
- public int taskStackMaxDim;
- public float taskStackWidthPaddingPct;
- public int taskStackTopPaddingPx;
+ /** Insets */
+ public Rect systemInsets = new Rect();
+ public Rect displayRect = new Rect();
+ /** Layout */
+ boolean isLandscape;
+ boolean transposeRecentsLayoutWithOrientation;
+
+ /** Search bar */
+ int searchBarAppWidgetId = -1;
+ public int searchBarSpaceHeightPx;
+
+ /** Task stack */
+ public int taskStackMaxDim;
+ public int taskStackTopPaddingPx;
+ public float taskStackWidthPaddingPct;
+
+ /** Task view animation and styles */
+ public int taskViewEnterFromHomeDuration;
+ public int taskViewEnterFromHomeDelay;
+ public int taskViewExitToHomeDuration;
public int taskViewRemoveAnimDuration;
public int taskViewRemoveAnimTranslationXPx;
public int taskViewTranslationZMinPx;
@@ -66,23 +79,30 @@
public int taskViewRoundedCornerRadiusPx;
public int taskViewHighlightPx;
- public int searchBarSpaceHeightPx;
-
+ /** Task bar colors */
public int taskBarViewDefaultBackgroundColor;
public int taskBarViewDefaultTextColor;
public int taskBarViewLightTextColor;
public int taskBarViewDarkTextColor;
public int taskBarViewHighlightColor;
+ /** Task bar animations */
public int taskBarEnterAnimDuration;
public int taskBarEnterAnimDelay;
public int taskBarExitAnimDuration;
+ public int taskBarDismissDozeDelaySeconds;
+ /** Nav bar scrim */
public int navBarScrimEnterDuration;
- public boolean launchedFromAltTab;
- public boolean launchedWithThumbnailAnimation;
+ /** Launch states */
+ public boolean launchedWithAltTab;
+ public boolean launchedWithNoRecentTasks;
+ public boolean launchedFromAppWithThumbnail;
+ public boolean launchedFromAppWithScreenshot;
+ public boolean launchedFromHome;
+ /** Dev options */
public boolean developerOptionsEnabled;
/** Private constructor */
@@ -108,33 +128,56 @@
DisplayMetrics dm = res.getDisplayMetrics();
mDisplayMetrics = dm;
- isLandscape = res.getConfiguration().orientation ==
- Configuration.ORIENTATION_LANDSCAPE;
- transposeRecentsLayoutWithOrientation =
- res.getBoolean(R.bool.recents_transpose_layout_with_orientation);
- if (Console.Enabled) {
- Console.log(Constants.Log.UI.MeasureAndLayout,
- "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
- Console.AnsiGreen);
- }
-
- displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
+ // Animations
animationPxMovementPerSecond =
res.getDimensionPixelSize(R.dimen.recents_animation_movement_in_dps_per_second);
+
+ // Interpolators
+ fastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_slow_in);
+ fastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_linear_in);
+ linearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.linear_out_slow_in);
+ quintOutInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.decelerate_quint);
+
+ // Filtering
filteringCurrentViewsMinAnimDuration =
res.getInteger(R.integer.recents_filter_animate_current_views_min_duration);
filteringNewViewsMinAnimDuration =
res.getInteger(R.integer.recents_filter_animate_new_views_min_duration);
- taskStackScrollDismissInfoPaneDistance = res.getDimensionPixelSize(
- R.dimen.recents_task_stack_scroll_dismiss_info_pane_distance);
- taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
+ // Insets
+ displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
+ // Layout
+ isLandscape = res.getConfiguration().orientation ==
+ Configuration.ORIENTATION_LANDSCAPE;
+ transposeRecentsLayoutWithOrientation =
+ res.getBoolean(R.bool.recents_transpose_layout_with_orientation);
+
+ // Search bar
+ searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
+
+ // Update the search widget id
+ SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
+ searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1);
+
+ // Task stack
TypedValue widthPaddingPctValue = new TypedValue();
res.getValue(R.dimen.recents_stack_width_padding_percentage, widthPaddingPctValue, true);
taskStackWidthPaddingPct = widthPaddingPctValue.getFloat();
+ taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
taskStackTopPaddingPx = res.getDimensionPixelSize(R.dimen.recents_stack_top_padding);
+ // Task view animation and styles
+ taskViewEnterFromHomeDuration =
+ res.getInteger(R.integer.recents_animate_task_enter_from_home_duration);
+ taskViewEnterFromHomeDelay =
+ res.getInteger(R.integer.recents_animate_task_enter_from_home_delay);
+ taskViewExitToHomeDuration =
+ res.getInteger(R.integer.recents_animate_task_exit_to_home_duration);
taskViewRemoveAnimDuration =
res.getInteger(R.integer.recents_animate_task_view_remove_duration);
taskViewRemoveAnimTranslationXPx =
@@ -148,8 +191,7 @@
taskViewShadowOutlineBottomInsetPx =
res.getDimensionPixelSize(R.dimen.recents_task_view_shadow_outline_bottom_inset);
- searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
-
+ // Task bar colors
taskBarViewDefaultBackgroundColor =
res.getColor(R.color.recents_task_bar_default_background_color);
taskBarViewDefaultTextColor =
@@ -161,31 +203,30 @@
taskBarViewHighlightColor =
res.getColor(R.color.recents_task_bar_highlight_color);
+ // Task bar animations
taskBarEnterAnimDuration =
res.getInteger(R.integer.recents_animate_task_bar_enter_duration);
taskBarEnterAnimDelay =
res.getInteger(R.integer.recents_animate_task_bar_enter_delay);
taskBarExitAnimDuration =
res.getInteger(R.integer.recents_animate_task_bar_exit_duration);
+ taskBarDismissDozeDelaySeconds =
+ res.getInteger(R.integer.recents_task_bar_dismiss_delay_seconds);
+ // Nav bar scrim
navBarScrimEnterDuration =
res.getInteger(R.integer.recents_nav_bar_scrim_enter_duration);
- fastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
- fastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_linear_in);
- linearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.linear_out_slow_in);
-
// Check if the developer options are enabled
ContentResolver cr = context.getContentResolver();
developerOptionsEnabled = Settings.Global.getInt(cr,
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
- // Update the search widget id
- SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
- searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1);
+ if (Console.Enabled) {
+ Console.log(Constants.Log.UI.MeasureAndLayout,
+ "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
+ Console.AnsiGreen);
+ }
}
/** Updates the system insets */
@@ -204,8 +245,11 @@
/** Called when the configuration has changed, and we want to reset any configuration specific
* members. */
public void updateOnConfigurationChange() {
- launchedFromAltTab = false;
- launchedWithThumbnailAnimation = false;
+ launchedWithAltTab = false;
+ launchedWithNoRecentTasks = false;
+ launchedFromAppWithThumbnail = false;
+ launchedFromAppWithScreenshot = false;
+ launchedFromHome = false;
}
/** Returns whether the search bar app widget exists. */
@@ -213,9 +257,16 @@
return searchBarAppWidgetId >= 0;
}
+ /** Returns whether the nav bar scrim should be animated when shown for the first time. */
+ public boolean shouldAnimateNavBarScrim() {
+ return true;
+ }
+
/** Returns whether the nav bar scrim should be visible. */
public boolean hasNavBarScrim() {
- return !transposeRecentsLayoutWithOrientation || !isLandscape;
+ // Only show the scrim if we have recent tasks, and if the nav bar is not transposed
+ return !launchedWithNoRecentTasks &&
+ (!transposeRecentsLayoutWithOrientation || !isLandscape);
}
/**
@@ -257,15 +308,4 @@
searchBarSpaceBounds.set(0, 0, width, searchBarSpaceHeightPx);
}
}
-
- /** Converts from DPs to PXs */
- public int pxFromDp(float size) {
- return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- size, mDisplayMetrics));
- }
- /** Converts from SPs to PXs */
- public int pxFromSp(float size) {
- return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
- size, mDisplayMetrics));
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 0c2c11d..e554af7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -121,6 +121,7 @@
// Send a broadcast to hide recents
Intent intent = new Intent(RecentsService.ACTION_HIDE_RECENTS_ACTIVITY);
intent.setPackage(context.getPackageName());
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
if (msg.arg1 != 0) {
intent.putExtra(RecentsService.EXTRA_TRIGGERED_FROM_ALT_TAB, true);
}
@@ -129,17 +130,21 @@
// Send a broadcast to toggle recents
Intent intent = new Intent(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY);
intent.setPackage(context.getPackageName());
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
context.sendBroadcast(intent);
// Time this path
- Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
- Constants.Log.App.TimeRecentsStartupKey, "receivedToggleRecents");
- Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
- Constants.Log.App.TimeRecentsLaunchKey, "receivedToggleRecents");
+ if (Console.Enabled) {
+ Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+ Constants.Log.App.TimeRecentsStartupKey, "receivedToggleRecents");
+ Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey, "receivedToggleRecents");
+ }
} else if (msg.what == AlternateRecentsComponent.MSG_START_ENTER_ANIMATION) {
// Send a broadcast to start the enter animation
Intent intent = new Intent(RecentsService.ACTION_START_ENTER_ANIMATION);
intent.setPackage(context.getPackageName());
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
context.sendBroadcast(intent);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index 4685186..a02e1a7b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -394,7 +394,7 @@
SystemServicesProxy ssp = mSystemServicesProxy;
List<ActivityManager.RecentTaskInfo> tasks =
- ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier());
+ ssp.getRecentTasks(100, UserHandle.CURRENT.getIdentifier());
Collections.reverse(tasks);
if (Console.Enabled) {
Console.log(Constants.Log.App.TimeSystemCalls,
@@ -478,7 +478,7 @@
// Load the thumbnail (if possible and not the foremost task, from the cache)
if (!isForemostTask) {
task.thumbnail = mThumbnailCache.get(task.key);
- if (task.thumbnail != null) {
+ if (task.thumbnail != null && !tasksToForceLoad.contains(task)) {
// Even though we get things from the cache, we should update them if
// they've changed in the bg
tasksToForceLoad.add(task);
@@ -489,6 +489,7 @@
Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|loadingTaskThumbnail]");
}
+
task.thumbnail = ssp.getTaskThumbnail(task.key.id);
if (task.thumbnail != null) {
task.thumbnail.setHasAlpha(false);
@@ -512,20 +513,6 @@
"" + (System.currentTimeMillis() - t1) + "ms");
}
- /*
- // Get all the stacks
- t1 = System.currentTimeMillis();
- List<ActivityManager.StackInfo> stackInfos = ams.getAllStackInfos();
- Console.log(Constants.Log.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms");
- Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size());
- for (ActivityManager.StackInfo s : stackInfos) {
- Console.log(Constants.Log.App.TaskDataLoader, " [RecentsTaskLoader|stack]", s.toString());
- if (stacks.containsKey(s.stackId)) {
- stacks.get(s.stackId).setRect(s.bounds);
- }
- }
- */
-
// Start the task loader
mLoader.start(context);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ReferenceCountedTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/ReferenceCountedTrigger.java
new file mode 100644
index 0000000..2f89e6d2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/ReferenceCountedTrigger.java
@@ -0,0 +1,92 @@
+/*
+ * 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.systemui.recents;
+
+import android.content.Context;
+
+/**
+ * A ref counted trigger that does some logic when the count is first incremented, or last
+ * decremented. Not thread safe as it's not currently needed.
+ */
+public class ReferenceCountedTrigger {
+
+ Context mContext;
+ int mCount;
+ Runnable mFirstIncRunnable;
+ Runnable mLastDecRunnable;
+ Runnable mErrorRunnable;
+
+ // Convenience runnables
+ Runnable mIncrementRunnable = new Runnable() {
+ @Override
+ public void run() {
+ increment();
+ }
+ };
+ Runnable mDecrementRunnable = new Runnable() {
+ @Override
+ public void run() {
+ decrement();
+ }
+ };
+
+ public ReferenceCountedTrigger(Context context, Runnable firstIncRunnable,
+ Runnable lastDecRunnable, Runnable errorRunanable) {
+ mContext = context;
+ mFirstIncRunnable = firstIncRunnable;
+ mLastDecRunnable = lastDecRunnable;
+ mErrorRunnable = errorRunanable;
+ }
+
+ /** Increments the ref count */
+ public void increment() {
+ if (mCount == 0 && mFirstIncRunnable != null) {
+ mFirstIncRunnable.run();
+ }
+ mCount++;
+ }
+
+ /** Convenience method to increment this trigger as a runnable */
+ public Runnable incrementAsRunnable() {
+ return mIncrementRunnable;
+ }
+
+ /** Decrements the ref count */
+ public void decrement() {
+ mCount--;
+ if (mCount == 0 && mLastDecRunnable != null) {
+ mLastDecRunnable.run();
+ } else if (mCount < 0) {
+ if (mErrorRunnable != null) {
+ mErrorRunnable.run();
+ } else {
+ new Throwable("Invalid ref count").printStackTrace();
+ Console.logError(mContext, "Invalid ref count");
+ }
+ }
+ }
+
+ /** Convenience method to decrement this trigger as a runnable */
+ public Runnable decrementAsRunnable() {
+ return mDecrementRunnable;
+ }
+
+ /** Returns the current ref count */
+ public int getCount() {
+ return mCount;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index 7a3ffb8..c47f7d7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -30,13 +30,23 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.Log;
import android.util.Pair;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
import java.util.ArrayList;
import java.util.Iterator;
@@ -48,16 +58,22 @@
* a point of injection when testing UI.
*/
public class SystemServicesProxy {
+ final static String TAG = "SystemServicesProxy";
+
ActivityManager mAm;
AppWidgetManager mAwm;
PackageManager mPm;
IPackageManager mIpm;
UserManager mUm;
SearchManager mSm;
+ WindowManager mWm;
+ Display mDisplay;
String mRecentsPackage;
ComponentName mAssistComponent;
Bitmap mDummyIcon;
+ Paint mBgProtectionPaint;
+ Canvas mBgProtectionCanvas;
/** Private constructor */
public SystemServicesProxy(Context context) {
@@ -67,8 +83,16 @@
mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
mIpm = AppGlobals.getPackageManager();
mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
+ mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ mDisplay = mWm.getDefaultDisplay();
mRecentsPackage = context.getPackageName();
+ // Create the protection paints
+ mBgProtectionPaint = new Paint();
+ mBgProtectionPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
+ mBgProtectionPaint.setColor(0xFFffffff);
+ mBgProtectionCanvas = new Canvas();
+
// Resolve the assist intent
Intent assist = mSm.getAssistIntent(context, false);
if (assist != null) {
@@ -184,7 +208,20 @@
return thumbnail;
}
- return mAm.getTaskTopThumbnail(taskId);
+ Bitmap thumbnail = mAm.getTaskTopThumbnail(taskId);
+ if (thumbnail != null) {
+ // We use a dumb heuristic for now, if the thumbnail is purely transparent in the top
+ // left pixel, then assume the whole thumbnail is transparent. Generally, proper
+ // screenshots are always composed onto a bitmap that has no alpha.
+ if (Color.alpha(thumbnail.getPixel(0, 0)) == 0) {
+ mBgProtectionCanvas.setBitmap(thumbnail);
+ mBgProtectionCanvas.drawRect(0, 0, thumbnail.getWidth(), thumbnail.getHeight(),
+ mBgProtectionPaint);
+ mBgProtectionCanvas.setBitmap(null);
+ Log.e(TAG, "Invalid screenshot detected from getTaskThumbnail()");
+ }
+ }
+ return thumbnail;
}
/** Moves a task to the front with the specified activity options */
@@ -325,4 +362,13 @@
// Delete the app widget
host.deleteAppWidgetId(appWidgetId);
}
+
+ /**
+ * Takes a screenshot of the current surface.
+ */
+ public Bitmap takeScreenshot() {
+ DisplayInfo di = new DisplayInfo();
+ mDisplay.getDisplayInfo(di);
+ return SurfaceControl.screenshot(di.getNaturalWidth(), di.getNaturalHeight());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java b/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java
index 1dd1be6..20be415 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java
@@ -56,6 +56,13 @@
return mStack;
}
+ /** Returns whether there are any tasks in any stacks below this node. */
+ public boolean hasTasks() {
+ return (mStack.getTaskCount() > 0) ||
+ (mStartNode != null && mStartNode.hasTasks()) ||
+ (mEndNode != null && mEndNode.hasTasks());
+ }
+
/** Returns whether this is a leaf node */
boolean isLeafNode() {
return (mStartNode == null) && (mEndNode == null);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 47a506c..f366ef0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -16,6 +16,7 @@
package com.android.systemui.recents.model;
+import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FullScreenTransitionView.java b/packages/SystemUI/src/com/android/systemui/recents/views/FullScreenTransitionView.java
new file mode 100644
index 0000000..c861d2c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FullScreenTransitionView.java
@@ -0,0 +1,238 @@
+/*
+ * 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.systemui.recents.views;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import com.android.systemui.recents.Console;
+import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsConfiguration;
+
+
+/**
+ * The full screen transition view that gets animated down from the full screen into a task
+ * thumbnail view.
+ */
+public class FullScreenTransitionView extends FrameLayout {
+
+ /** The FullScreenTransitionView callbacks */
+ public interface FullScreenTransitionViewCallbacks {
+ void onEnterAnimationComplete(boolean canceled);
+ }
+
+ RecentsConfiguration mConfig;
+
+ FullScreenTransitionViewCallbacks mCb;
+
+ ImageView mScreenshotView;
+
+ Rect mClipRect = new Rect();
+
+ boolean mIsAnimating;
+ AnimatorSet mEnterAnimation;
+
+ public FullScreenTransitionView(Context context, FullScreenTransitionViewCallbacks cb) {
+ super(context);
+ mConfig = RecentsConfiguration.getInstance();
+ mCb = cb;
+ mScreenshotView = new ImageView(context);
+ mScreenshotView.setScaleType(ImageView.ScaleType.FIT_XY);
+ mScreenshotView.setLayoutParams(new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+ addView(mScreenshotView);
+ setClipTop(getClipTop());
+ setClipBottom(getClipBottom());
+ setWillNotDraw(false);
+ }
+
+ /** Sets the top clip */
+ public void setClipTop(int clip) {
+ mClipRect.top = clip;
+ postInvalidateOnAnimation();
+ }
+
+ /** Gets the top clip */
+ public int getClipTop() {
+ return mClipRect.top;
+ }
+
+ /** Sets the bottom clip */
+ public void setClipBottom(int clip) {
+ mClipRect.bottom = clip;
+ postInvalidateOnAnimation();
+ }
+
+ /** Gets the top clip */
+ public int getClipBottom() {
+ return mClipRect.bottom;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ mClipRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ int restoreCount = canvas.save(Canvas.CLIP_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+ canvas.clipRect(mClipRect);
+ super.draw(canvas);
+ canvas.restoreToCount(restoreCount);
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ /** Prepares the screenshot view for the transition into Recents */
+ public void prepareAnimateOnEnterRecents(Bitmap screenshot) {
+ if (!mConfig.launchedFromAppWithScreenshot) return;
+
+ if (Console.Enabled) {
+ Console.logStartTracingTime(Constants.Log.App.TimeRecentsScreenshotTransition,
+ Constants.Log.App.TimeRecentsScreenshotTransitionKey);
+ }
+
+ setClipTop(0);
+ setClipBottom(getMeasuredHeight());
+ setTranslationY(0f);
+ setScaleX(1f);
+ setScaleY(1f);
+ setVisibility(mConfig.launchedFromAppWithScreenshot ? View.VISIBLE : View.INVISIBLE);
+ if (screenshot != null) {
+ mScreenshotView.setImageBitmap(screenshot);
+ } else {
+ mScreenshotView.setImageDrawable(null);
+ }
+ }
+
+ /** Resets the transition view */
+ public void reset() {
+ setVisibility(View.INVISIBLE);
+ mScreenshotView.setImageDrawable(null);
+ }
+
+ /** Animates this view as it enters recents */
+ public void animateOnEnterRecents(ViewAnimation.TaskViewEnterContext ctx,
+ final Runnable postAnimRunnable) {
+ if (Console.Enabled) {
+ Console.logTraceTime(Constants.Log.App.TimeRecentsScreenshotTransition,
+ Constants.Log.App.TimeRecentsScreenshotTransitionKey, "Starting");
+ }
+
+ // Cancel the current animation
+ if (mEnterAnimation != null) {
+ mEnterAnimation.removeAllListeners();
+ mEnterAnimation.cancel();
+ }
+
+ // Calculate the bottom clip
+ float scale = (float) ctx.taskRect.width() / getMeasuredWidth();
+ int translationY = -mConfig.systemInsets.top + ctx.stackRectSansPeek.top +
+ ctx.transform.translationY;
+ int clipBottom = mConfig.systemInsets.top + (int) (ctx.taskRect.height() / scale);
+
+ // Enable the HW Layers on the screenshot view
+ mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+
+ // Compose the animation
+ mEnterAnimation = new AnimatorSet();
+ mEnterAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Notify any callbacks
+ mCb.onEnterAnimationComplete(false);
+ // Run the given post-anim runnable
+ postAnimRunnable.run();
+ // Mark that we are no longer animating
+ mIsAnimating = false;
+ // Disable the HW Layers on this view
+ setLayerType(View.LAYER_TYPE_NONE, null);
+
+ if (Console.Enabled) {
+ Console.logTraceTime(Constants.Log.App.TimeRecentsScreenshotTransition,
+ Constants.Log.App.TimeRecentsScreenshotTransitionKey, "Completed");
+ }
+ }
+ });
+ mEnterAnimation.setStartDelay(0);
+ mEnterAnimation.setDuration(475);
+ mEnterAnimation.setInterpolator(mConfig.fastOutSlowInInterpolator);
+ mEnterAnimation.playTogether(
+ ObjectAnimator.ofInt(this, "clipTop", mConfig.systemInsets.top),
+ ObjectAnimator.ofInt(this, "clipBottom", clipBottom),
+ ObjectAnimator.ofFloat(this, "translationY", translationY),
+ ObjectAnimator.ofFloat(this, "scaleX", scale),
+ ObjectAnimator.ofFloat(this, "scaleY", scale)
+ );
+ mEnterAnimation.start();
+
+ mIsAnimating = true;
+ }
+
+ /** Animates this view back out of Recents if we were in the process of animating in. */
+ public boolean cancelAnimateOnEnterRecents(final Runnable postAnimRunnable) {
+ if (mIsAnimating) {
+ // Cancel the current animation
+ if (mEnterAnimation != null) {
+ mEnterAnimation.removeAllListeners();
+ mEnterAnimation.cancel();
+ }
+
+ // Compose the animation
+ mEnterAnimation = new AnimatorSet();
+ mEnterAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Notify any callbacks
+ mCb.onEnterAnimationComplete(true);
+ // Run the given post-anim runnable
+ postAnimRunnable.run();
+ // Mark that we are no longer animating
+ mIsAnimating = false;
+ // Disable the HW Layers on the screenshot view
+ mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ });
+ mEnterAnimation.setDuration(475);
+ mEnterAnimation.setInterpolator(mConfig.fastOutSlowInInterpolator);
+ mEnterAnimation.playTogether(
+ ObjectAnimator.ofInt(this, "clipTop", 0),
+ ObjectAnimator.ofInt(this, "clipBottom", getMeasuredHeight()),
+ ObjectAnimator.ofFloat(this, "translationY", 0f),
+ ObjectAnimator.ofFloat(this, "scaleX", 1f),
+ ObjectAnimator.ofFloat(this, "scaleY", 1f)
+ );
+ mEnterAnimation.start();
+
+ return true;
+ }
+ return false;
+ }
+}
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 db398b1..3e6879d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -55,9 +55,12 @@
/** The RecentsView callbacks */
public interface RecentsViewCallbacks {
public void onTaskLaunching(boolean isTaskInStackBounds);
- public void onEnterAnimationTriggered();
+ public void onExitAnimationTriggered();
}
+ RecentsConfiguration mConfig;
+ LayoutInflater mInflater;
+
// The space partitioning root of this container
SpaceNode mBSP;
// Whether there are any tasks
@@ -67,12 +70,10 @@
// Recents view callbacks
RecentsViewCallbacks mCb;
- LayoutInflater mInflater;
-
public RecentsView(Context context) {
super(context);
+ mConfig = RecentsConfiguration.getInstance();
mInflater = LayoutInflater.from(context);
- setWillNotDraw(false);
}
/** Sets the callbacks */
@@ -160,20 +161,42 @@
}
/** Requests all task stacks to start their enter-recents animation */
- public void startOnEnterAnimation() {
- // Notify callbacks that we are starting the enter animation
- mCb.onEnterAnimationTriggered();
-
+ public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child instanceof TaskStackView) {
TaskStackView stackView = (TaskStackView) child;
- stackView.startOnEnterAnimation();
+ stackView.startEnterRecentsAnimation(ctx);
}
}
}
+ /** Requests all task stacks to start their exit-recents animation */
+ public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
+ // Handle the case when there are no views by incrementing and decrementing after all
+ // animations are started.
+ ctx.postAnimationTrigger.increment();
+
+ if (Constants.DebugFlags.App.EnableHomeTransition) {
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ if (child instanceof TaskStackView) {
+ TaskStackView stackView = (TaskStackView) child;
+ stackView.startExitToHomeAnimation(ctx);
+ }
+ }
+ }
+
+ // Handle the case when there are no views by incrementing and decrementing after all
+ // animations are started.
+ ctx.postAnimationTrigger.decrement();
+
+ // Notify of the exit animation
+ mCb.onExitAnimationTriggered();
+ }
+
/** Adds the search bar */
public void setSearchBar(View searchBar) {
// Create the search bar (and hide it if we have no recent tasks)
@@ -215,10 +238,9 @@
}
// Get the search bar bounds and measure the search bar layout
- RecentsConfiguration config = RecentsConfiguration.getInstance();
if (mSearchBar != null) {
Rect searchBarSpaceBounds = new Rect();
- config.getSearchBarBounds(width, height - config.systemInsets.top, searchBarSpaceBounds);
+ mConfig.getSearchBarBounds(width, height - mConfig.systemInsets.top, searchBarSpaceBounds);
mSearchBar.measure(
MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), MeasureSpec.EXACTLY));
@@ -229,9 +251,9 @@
// In addition, we give it the full height, not including the top inset or search bar space,
// since we want the tasks to render under the navigation buttons in portrait.
Rect taskStackBounds = new Rect();
- config.getTaskStackBounds(width, height, taskStackBounds);
- int childWidth = width - config.systemInsets.right;
- int childHeight = taskStackBounds.height() - config.systemInsets.top;
+ mConfig.getTaskStackBounds(width, height, taskStackBounds);
+ int childWidth = width - mConfig.systemInsets.right;
+ int childHeight = taskStackBounds.height() - mConfig.systemInsets.top;
// Measure each TaskStackView
int childCount = getChildCount();
@@ -259,23 +281,22 @@
}
// Get the search bar bounds so that we lay it out
- RecentsConfiguration config = RecentsConfiguration.getInstance();
if (mSearchBar != null) {
Rect searchBarSpaceBounds = new Rect();
- config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(), searchBarSpaceBounds);
- mSearchBar.layout(config.systemInsets.left + searchBarSpaceBounds.left,
- config.systemInsets.top + searchBarSpaceBounds.top,
- config.systemInsets.left + mSearchBar.getMeasuredWidth(),
- config.systemInsets.top + mSearchBar.getMeasuredHeight());
+ mConfig.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(), searchBarSpaceBounds);
+ mSearchBar.layout(mConfig.systemInsets.left + searchBarSpaceBounds.left,
+ mConfig.systemInsets.top + searchBarSpaceBounds.top,
+ mConfig.systemInsets.left + mSearchBar.getMeasuredWidth(),
+ mConfig.systemInsets.top + mSearchBar.getMeasuredHeight());
}
// We offset the stack view by the left inset (if any), but lay it out under the search bar.
// In addition, we offset our stack views by the top inset and search bar height, but not
// the bottom insets because we want it to render under the navigation buttons.
Rect taskStackBounds = new Rect();
- config.getTaskStackBounds(getMeasuredWidth(), getMeasuredHeight(), taskStackBounds);
- left += config.systemInsets.left;
- top += config.systemInsets.top + taskStackBounds.top;
+ mConfig.getTaskStackBounds(getMeasuredWidth(), getMeasuredHeight(), taskStackBounds);
+ left += mConfig.systemInsets.left;
+ top += mConfig.systemInsets.top + taskStackBounds.top;
// Layout each child
// XXX: Based on the space node for that task view
@@ -289,6 +310,20 @@
}
}
+ /** Notifies each task view of the user interaction. */
+ public void onUserInteraction() {
+ // Get the first stack view
+ TaskStackView stackView = null;
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ if (child instanceof TaskStackView) {
+ stackView = (TaskStackView) child;
+ stackView.onUserInteraction();
+ }
+ }
+ }
+
/** Focuses the next task in the first stack view */
public void focusNextTask(boolean forward) {
// Get the first stack view
@@ -324,8 +359,7 @@
}
// Update the configuration with the latest system insets and trigger a relayout
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- config.updateSystemInsets(insets.getSystemWindowInsets());
+ mConfig.updateSystemInsets(insets.getSystemWindowInsets());
requestLayout();
return insets.consumeSystemWindowInsets(false, false, false, true);
@@ -365,6 +399,11 @@
final Runnable launchRunnable = new Runnable() {
@Override
public void run() {
+ if (Console.Enabled) {
+ Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey, "preStartActivity");
+ }
+
TaskViewTransform transform;
View sourceView = tv;
int offsetX = 0;
@@ -374,11 +413,10 @@
// If there is no actual task view, then use the stack view as the source view
// and then offset to the expected transform rect, but bound this to just
// outside the display rect (to ensure we don't animate from too far away)
- RecentsConfiguration config = RecentsConfiguration.getInstance();
sourceView = stackView;
transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
offsetX = transform.rect.left;
- offsetY = Math.min(transform.rect.top, config.displayRect.height());
+ offsetY = Math.min(transform.rect.top, mConfig.displayRect.height());
} else {
transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
}
@@ -426,19 +464,23 @@
onTaskRemoved(task);
}
- Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
- Constants.Log.App.TimeRecentsLaunchKey, "startActivity");
+ if (Console.Enabled) {
+ Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey, "startActivity");
+ }
}
};
- Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
- Constants.Log.App.TimeRecentsLaunchKey, "onTaskLaunched");
+ if (Console.Enabled) {
+ Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+ Constants.Log.App.TimeRecentsLaunchKey, "onTaskLaunched");
+ }
// Launch the app right away if there is no task view, otherwise, animate the icon out first
if (tv == null) {
post(launchRunnable);
} else {
- tv.animateOnLeavingRecents(launchRunnable);
+ stackView.animateOnLaunchingTask(tv, launchRunnable);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
index c10ddd1..82d6220 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -24,6 +24,8 @@
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewPropertyAnimator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
@@ -36,6 +38,9 @@
/* The task bar view */
class TaskBarView extends FrameLayout {
+
+ RecentsConfiguration mConfig;
+
Task mTask;
ImageView mDismissButton;
@@ -61,6 +66,7 @@
public TaskBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ mConfig = RecentsConfiguration.getInstance();
setWillNotDraw(false);
// Load the dismiss resources
@@ -70,11 +76,10 @@
// Configure the highlight paint
if (sHighlightPaint == null) {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
sHighlightPaint = new Paint();
sHighlightPaint.setStyle(Paint.Style.STROKE);
- sHighlightPaint.setStrokeWidth(config.taskViewHighlightPx);
- sHighlightPaint.setColor(config.taskBarViewHighlightColor);
+ sHighlightPaint.setStrokeWidth(mConfig.taskViewHighlightPx);
+ sHighlightPaint.setColor(mConfig.taskBarViewHighlightColor);
sHighlightPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
sHighlightPaint.setAntiAlias(true);
}
@@ -90,39 +95,42 @@
@Override
protected void onDraw(Canvas canvas) {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
-
// Draw the highlight at the top edge (but put the bottom edge just out of view)
- float offset = config.taskViewHighlightPx / 2f;
- float radius = config.taskViewRoundedCornerRadiusPx;
+ float offset = mConfig.taskViewHighlightPx / 2f;
+ float radius = mConfig.taskViewRoundedCornerRadiusPx;
canvas.drawRoundRect(-offset, 0f, (float) getMeasuredWidth() + offset,
getMeasuredHeight() + radius, radius, radius, sHighlightPaint);
}
/** Synchronizes this bar view's properties with the task's transform */
- void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
- TaskViewTransform toTransform, int duration) {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- if (duration > 0) {
- if (animateFromTransform != null) {
- mDismissButton.setAlpha(animateFromTransform.dismissAlpha);
- }
- mDismissButton.animate()
- .alpha(toTransform.dismissAlpha)
+ void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration) {
+ if (duration > 0 && (mDismissButton.getVisibility() == View.VISIBLE)) {
+ ViewPropertyAnimator anim = mDismissButton.animate();
+
+ // Animate to the final state
+ if (toTransform.hasDismissAlphaChangedFrom(mDismissButton.getAlpha())) {
+ anim.alpha(toTransform.dismissAlpha)
.setStartDelay(0)
.setDuration(duration)
- .setInterpolator(config.fastOutSlowInInterpolator)
+ .setInterpolator(mConfig.fastOutSlowInInterpolator)
.withLayer()
.start();
+ }
} else {
- mDismissButton.setAlpha(toTransform.dismissAlpha);
+ // Set the changed properties
+ if (toTransform.hasDismissAlphaChangedFrom(mDismissButton.getAlpha())) {
+ mDismissButton.setAlpha(toTransform.dismissAlpha);
+ }
}
- mDismissButton.invalidate();
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
}
/** Binds the bar view to the task */
void rebindToTask(Task t, boolean animate) {
- RecentsConfiguration configuration = RecentsConfiguration.getInstance();
mTask = t;
// If an activity icon is defined, then we use that as the primary icon to show in the bar,
// otherwise, we fall back to the application icon
@@ -137,15 +145,12 @@
if (Constants.DebugFlags.App.EnableTaskBarThemeColors && tint != 0) {
setBackgroundColor(tint);
mActivityDescription.setTextColor(Utilities.getIdealColorForBackgroundColor(tint,
- configuration.taskBarViewLightTextColor, configuration.taskBarViewDarkTextColor));
+ mConfig.taskBarViewLightTextColor, mConfig.taskBarViewDarkTextColor));
mDismissButton.setImageDrawable(Utilities.getIdealResourceForBackgroundColor(tint,
mLightDismissDrawable, mDarkDismissDrawable));
} else {
- setBackgroundColor(configuration.taskBarViewDefaultBackgroundColor);
- mActivityDescription.setTextColor(configuration.taskBarViewDefaultTextColor);
- }
- if (animate) {
- // XXX: Investigate how expensive it will be to create a second bitmap and crossfade
+ setBackgroundColor(mConfig.taskBarViewDefaultBackgroundColor);
+ mActivityDescription.setTextColor(mConfig.taskBarViewDefaultTextColor);
}
}
@@ -155,4 +160,88 @@
mApplicationIcon.setImageDrawable(null);
mActivityDescription.setText("");
}
+
+ /** Prepares this task view for the enter-recents animations. This is called earlier in the
+ * first layout because the actual animation into recents may take a long time. */
+ public void prepareEnterRecentsAnimation() {
+ setVisibility(View.INVISIBLE);
+ }
+
+ /** Animates this task bar as it enters recents */
+ public void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) {
+ // Animate the task bar of the first task view
+ setVisibility(View.VISIBLE);
+ setTranslationY(-getMeasuredHeight());
+ animate()
+ .translationY(0)
+ .setStartDelay(delay)
+ .setInterpolator(mConfig.fastOutSlowInInterpolator)
+ .setDuration(mConfig.taskBarEnterAnimDuration)
+ .withEndAction(postAnimRunnable)
+ .start();
+ }
+
+ /** Animates this task bar as it exits recents */
+ public void startLaunchTaskAnimation(Runnable preAnimRunnable, final Runnable postAnimRunnable) {
+ // Animate the task bar out of the first task view
+ animate()
+ .translationY(-getMeasuredHeight())
+ .setStartDelay(0)
+ .setInterpolator(mConfig.fastOutLinearInInterpolator)
+ .setDuration(mConfig.taskBarExitAnimDuration)
+ .withStartAction(preAnimRunnable)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ post(postAnimRunnable);
+ }
+ })
+ .start();
+ }
+
+ /** Animates this task bar dismiss button when launching a task. */
+ public void startLaunchTaskDismissAnimation() {
+ if (mDismissButton.getVisibility() == View.VISIBLE) {
+ mDismissButton.animate().cancel();
+ mDismissButton.animate()
+ .alpha(0f)
+ .setStartDelay(0)
+ .setInterpolator(mConfig.fastOutSlowInInterpolator)
+ .setDuration(mConfig.taskBarExitAnimDuration)
+ .withLayer()
+ .start();
+ }
+ }
+
+ /** Animates this task bar if the user does not interact with the stack after a certain time. */
+ public void startNoUserInteractionAnimation() {
+ mDismissButton.setVisibility(View.VISIBLE);
+ mDismissButton.setAlpha(0f);
+ mDismissButton.animate()
+ .alpha(1f)
+ .setStartDelay(0)
+ .setInterpolator(mConfig.fastOutLinearInInterpolator)
+ .setDuration(mConfig.taskBarEnterAnimDuration)
+ .withLayer()
+ .start();
+ }
+
+ /** Mark this task view that the user does has not interacted with the stack after a certain time. */
+ public void setNoUserInteractionState() {
+ if (mDismissButton.getVisibility() != View.VISIBLE) {
+ mDismissButton.animate().cancel();
+ mDismissButton.setVisibility(View.VISIBLE);
+ mDismissButton.setAlpha(1f);
+ }
+ }
+
+ /** Enable the hw layers on this task view */
+ void enableHwLayers() {
+ mDismissButton.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ }
+
+ /** Disable the hw layers on this task view */
+ void disableHwLayers() {
+ mDismissButton.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 5830e37..e0a12b7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -38,9 +38,11 @@
import com.android.systemui.R;
import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.DozeTrigger;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.RecentsPackageMonitor;
import com.android.systemui.recents.RecentsTaskLoader;
+import com.android.systemui.recents.ReferenceCountedTrigger;
import com.android.systemui.recents.Utilities;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
@@ -62,10 +64,14 @@
public void onTaskRemoved(Task t);
}
+ RecentsConfiguration mConfig;
+
TaskStack mStack;
TaskStackViewTouchHandler mTouchHandler;
TaskStackViewCallbacks mCb;
ViewPool<TaskView, Task> mViewPool;
+ ArrayList<TaskViewTransform> mTaskTransforms = new ArrayList<TaskViewTransform>();
+ DozeTrigger mDozeTrigger;
// The various rects that define the stack view
Rect mRect = new Rect();
@@ -83,11 +89,12 @@
ObjectAnimator mScrollAnimator;
// Optimizations
- int mHwLayersRefCount;
+ ReferenceCountedTrigger mHwLayersTrigger;
int mStackViewsAnimationDuration;
boolean mStackViewsDirty = true;
boolean mAwaitingFirstLayout = true;
boolean mStartEnterAnimationRequestedAfterLayout;
+ ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext;
int[] mTmpVisibleRange = new int[2];
Rect mTmpRect = new Rect();
Rect mTmpRect2 = new Rect();
@@ -95,12 +102,51 @@
public TaskStackView(Context context, TaskStack stack) {
super(context);
+ mConfig = RecentsConfiguration.getInstance();
mStack = stack;
mStack.setCallbacks(this);
mScroller = new OverScroller(context);
mTouchHandler = new TaskStackViewTouchHandler(context, this);
mViewPool = new ViewPool<TaskView, Task>(context, this);
mInflater = LayoutInflater.from(context);
+ mDozeTrigger = new DozeTrigger(mConfig.taskBarDismissDozeDelaySeconds, new Runnable() {
+ @Override
+ public void run() {
+ // Show the task bar dismiss buttons
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ TaskView tv = (TaskView) getChildAt(i);
+ tv.startNoUserInteractionAnimation();
+ }
+ }
+ });
+ mHwLayersTrigger = new ReferenceCountedTrigger(getContext(), new Runnable() {
+ @Override
+ public void run() {
+ // Enable hw layers on each of the children
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ TaskView tv = (TaskView) getChildAt(i);
+ tv.enableHwLayers();
+ }
+ }
+ }, new Runnable() {
+ @Override
+ public void run() {
+ // Disable hw layers on each of the children
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ TaskView tv = (TaskView) getChildAt(i);
+ tv.disableHwLayers();
+ }
+ }
+ }, new Runnable() {
+ @Override
+ public void run() {
+ new Throwable("Invalid hw layers ref count").printStackTrace();
+ Console.logError(getContext(), "Invalid HW layers ref count");
+ }
+ });
}
/** Sets the callbacks */
@@ -118,7 +164,7 @@
"[TaskStackView|requestSynchronize]", "" + duration + "ms", Console.AnsiYellow);
}
if (!mStackViewsDirty) {
- invalidate();
+ invalidate(mStackRect);
}
if (mAwaitingFirstLayout) {
// Skip the animation if we are awaiting first layout
@@ -129,7 +175,7 @@
mStackViewsDirty = true;
}
- // XXX: Optimization: Use a mapping of Task -> View
+ /** Finds the child view given a specific task */
private TaskView getChildViewForTask(Task t) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -156,14 +202,16 @@
float boundedT = Math.max(t, -(numPeekCards + 1));
// Set the scale relative to its position
+ int numFrontScaledCards = 3;
float minScale = Constants.Values.TaskStackView.StackPeekMinScale;
float scaleRange = 1f - minScale;
- float scaleInc = scaleRange / numPeekCards;
- float scale = Math.max(minScale, Math.min(1f, 1f + (boundedT * scaleInc)));
+ float scaleInc = scaleRange / (numPeekCards + numFrontScaledCards);
+ float scale = Math.max(minScale, Math.min(1f, minScale +
+ ((boundedT + (numPeekCards + 1)) * scaleInc)));
float scaleYOffset = ((1f - scale) * mTaskRect.height()) / 2;
transform.scale = scale;
- // Set the translation
+ // Set the y translation
if (boundedT < 0f) {
transform.translationY = (int) ((Math.max(-numPeekCards, boundedT) /
numPeekCards) * peekHeight - scaleYOffset);
@@ -171,6 +219,11 @@
transform.translationY = (int) (boundedT * overlapHeight - scaleYOffset);
}
+ // Set the z translation
+ int minZ = mConfig.taskViewTranslationZMinPx;
+ int incZ = mConfig.taskViewTranslationZIncrementPx;
+ transform.translationZ = (int) Math.max(minZ, minZ + ((boundedT + numPeekCards) * incZ));
+
// Set the alphas
transform.dismissAlpha = Math.max(-1f, Math.min(0f, t + 1)) + 1f;
@@ -190,16 +243,18 @@
/**
* Gets the stack transforms of a list of tasks, and returns the visible range of tasks.
*/
- private ArrayList<TaskViewTransform> getStackTransforms(ArrayList<Task> tasks,
- int stackScroll,
- int[] visibleRangeOut,
- boolean boundTranslationsToRect) {
+ private void updateStackTransforms(ArrayList<TaskViewTransform> taskTransforms,
+ ArrayList<Task> tasks,
+ int stackScroll,
+ int[] visibleRangeOut,
+ boolean boundTranslationsToRect) {
// XXX: Optimization: Use binary search to find the visible range
- ArrayList<TaskViewTransform> taskTransforms = new ArrayList<TaskViewTransform>();
int taskCount = tasks.size();
int firstVisibleIndex = -1;
int lastVisibleIndex = -1;
+ taskTransforms.clear();
+ taskTransforms.ensureCapacity(taskCount);
for (int i = 0; i < taskCount; i++) {
TaskViewTransform transform = getStackTransform(i, stackScroll);
taskTransforms.add(transform);
@@ -218,6 +273,19 @@
visibleRangeOut[0] = firstVisibleIndex;
visibleRangeOut[1] = lastVisibleIndex;
}
+ }
+
+ /**
+ * Gets the stack transforms of a list of tasks, and returns the visible range of tasks. This
+ * call is less optimal than calling updateStackTransforms directly.
+ */
+ private ArrayList<TaskViewTransform> getStackTransforms(ArrayList<Task> tasks,
+ int stackScroll,
+ int[] visibleRangeOut,
+ boolean boundTranslationsToRect) {
+ ArrayList<TaskViewTransform> taskTransforms = new ArrayList<TaskViewTransform>();
+ updateStackTransforms(taskTransforms, tasks, stackScroll, visibleRangeOut,
+ boundTranslationsToRect);
return taskTransforms;
}
@@ -237,14 +305,13 @@
int[] visibleRange = mTmpVisibleRange;
int stackScroll = getStackScroll();
ArrayList<Task> tasks = mStack.getTasks();
- ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(tasks, stackScroll,
- visibleRange, false);
+ updateStackTransforms(mTaskTransforms, tasks, stackScroll, visibleRange, false);
// Update the visible state of all the tasks
int taskCount = tasks.size();
for (int i = 0; i < taskCount; i++) {
Task task = tasks.get(i);
- TaskViewTransform transform = taskTransforms.get(i);
+ TaskViewTransform transform = mTaskTransforms.get(i);
TaskView tv = getChildViewForTask(task);
if (transform.visible) {
@@ -255,7 +322,7 @@
if (mStackViewsAnimationDuration > 0 && i != 0) {
int fromIndex = (transform.t < 0) ? (visibleRange[0] - 1) :
(visibleRange[1] + 1);
- tv.updateViewPropertiesToTaskTransform(null,
+ tv.updateViewPropertiesToTaskTransform(
getStackTransform(fromIndex, stackScroll), 0);
}
}
@@ -273,10 +340,10 @@
TaskView tv = (TaskView) getChildAt(i);
Task task = tv.getTask();
int taskIndex = mStack.indexOfTask(task);
- if (taskIndex < 0 || !taskTransforms.get(taskIndex).visible) {
+ if (taskIndex < 0 || !mTaskTransforms.get(taskIndex).visible) {
mViewPool.returnViewToPool(tv);
} else {
- tv.updateViewPropertiesToTaskTransform(null, taskTransforms.get(taskIndex),
+ tv.updateViewPropertiesToTaskTransform(mTaskTransforms.get(taskIndex),
mStackViewsAnimationDuration);
}
}
@@ -353,7 +420,7 @@
mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
mScrollAnimator.setDuration(Utilities.calculateTranslationAnimationDuration(newScroll -
curScroll, 250));
- mScrollAnimator.setInterpolator(RecentsConfiguration.getInstance().fastOutSlowInInterpolator);
+ mScrollAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
@@ -465,6 +532,20 @@
}
}
+ /** Animates a task view in this stack as it launches. */
+ public void animateOnLaunchingTask(TaskView tv, final Runnable r) {
+ // Hide each of the task bar dismiss buttons
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ TaskView t = (TaskView) getChildAt(i);
+ if (t == tv) {
+ t.startLaunchTaskAnimation(r, true);
+ } else {
+ t.startLaunchTaskAnimation(null, false);
+ }
+ }
+ }
+
/** Focuses the task at the specified index in the stack */
void focusTask(int taskIndex, boolean scrollToNewPosition) {
if (Console.Enabled) {
@@ -535,48 +616,31 @@
/** Enables the hw layers and increments the hw layer requirement ref count */
void addHwLayersRefCount(String reason) {
if (Console.Enabled) {
+ int refCount = mHwLayersTrigger.getCount();
Console.log(Constants.Log.UI.HwLayers,
"[TaskStackView|addHwLayersRefCount] refCount: " +
- mHwLayersRefCount + "->" + (mHwLayersRefCount + 1) + " " + reason);
+ refCount + "->" + (refCount + 1) + " " + reason);
}
- if (mHwLayersRefCount == 0) {
- // Enable hw layers on each of the children
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- TaskView tv = (TaskView) getChildAt(i);
- tv.enableHwLayers();
- }
- }
- mHwLayersRefCount++;
+ mHwLayersTrigger.increment();
}
/** Decrements the hw layer requirement ref count and disables the hw layers when we don't
need them anymore. */
void decHwLayersRefCount(String reason) {
if (Console.Enabled) {
+ int refCount = mHwLayersTrigger.getCount();
Console.log(Constants.Log.UI.HwLayers,
"[TaskStackView|decHwLayersRefCount] refCount: " +
- mHwLayersRefCount + "->" + (mHwLayersRefCount - 1) + " " + reason);
+ refCount + "->" + (refCount - 1) + " " + reason);
}
- mHwLayersRefCount--;
- if (mHwLayersRefCount == 0) {
- // Disable hw layers on each of the children
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- TaskView tv = (TaskView) getChildAt(i);
- tv.disableHwLayers();
- }
- } else if (mHwLayersRefCount < 0) {
- new Throwable("Invalid hw layers ref count").printStackTrace();
- Console.logError(getContext(), "Invalid HW layers ref count");
- }
+ mHwLayersTrigger.decrement();
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
setStackScroll(mScroller.getCurrY());
- invalidate();
+ invalidate(mStackRect);
// If we just finished scrolling, then disable the hw layers
if (mScroller.isFinished()) {
@@ -608,7 +672,6 @@
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
if (Constants.DebugFlags.App.EnableTaskStackClipping) {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
TaskView tv = (TaskView) child;
TaskView nextTv = null;
TaskView tmpTv = null;
@@ -624,13 +687,13 @@
}
// Clip against the next view (if we aren't animating its alpha)
- if (nextTv != null && nextTv.getAlpha() == 1f) {
+ if (nextTv != null) {
Rect curRect = tv.getClippingRect(mTmpRect);
Rect nextRect = nextTv.getClippingRect(mTmpRect2);
// The hit rects are relative to the task view, which needs to be offset by
// the system bar height
- curRect.offset(0, config.systemInsets.top);
- nextRect.offset(0, config.systemInsets.top);
+ curRect.offset(0, mConfig.systemInsets.top);
+ nextRect.offset(0, mConfig.systemInsets.top);
// Compute the clip region
Region clipRegion = new Region();
clipRegion.op(curRect, Region.Op.UNION);
@@ -652,7 +715,6 @@
// Note: We let the stack view be the full height because we want the cards to go under the
// navigation bar if possible. However, the stack rects which we use to calculate
// max scroll, etc. need to take the nav bar into account
- RecentsConfiguration config = RecentsConfiguration.getInstance();
// Compute the stack rects
mRect.set(0, 0, width, height);
@@ -660,8 +722,8 @@
mStackRect.left += insetLeft;
mStackRect.bottom -= insetBottom;
- int widthPadding = (int) (config.taskStackWidthPaddingPct * mStackRect.width());
- int heightPadding = config.taskStackTopPaddingPx;
+ int widthPadding = (int) (mConfig.taskStackWidthPaddingPct * mStackRect.width());
+ int heightPadding = mConfig.taskStackTopPaddingPx;
if (Constants.DebugFlags.App.EnableSearchLayout) {
mStackRect.top += heightPadding;
mStackRect.left += widthPadding;
@@ -699,10 +761,9 @@
}
// Compute our stack/task rects
- RecentsConfiguration config = RecentsConfiguration.getInstance();
Rect taskStackBounds = new Rect();
- config.getTaskStackBounds(width, height, taskStackBounds);
- computeRects(width, height, taskStackBounds.left, config.systemInsets.bottom);
+ mConfig.getTaskStackBounds(width, height, taskStackBounds);
+ computeRects(width, height, taskStackBounds.left, mConfig.systemInsets.bottom);
// Debug logging
if (Constants.Log.UI.MeasureAndLayout) {
@@ -760,47 +821,69 @@
}
if (mAwaitingFirstLayout) {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
-
- // Update the focused task index to be the next item to the top task
- if (config.launchedFromAltTab) {
- focusTask(Math.max(0, mStack.getTaskCount() - 2), false);
- }
-
- // Prepare the first view for its enter animation
- if (config.launchedWithThumbnailAnimation) {
- TaskView tv = (TaskView) getChildAt(getChildCount() - 1);
- if (tv != null) {
- tv.prepareAnimateOnEnterRecents();
- }
- }
-
// Mark that we have completely the first layout
mAwaitingFirstLayout = false;
+ // Start dozing
+ mDozeTrigger.startDozing();
+
+ // Prepare the first view for its enter animation
+ int offsetTopAlign = -mTaskRect.top;
+ int offscreenY = mRect.bottom - (mTaskRect.top - mRect.top);
+ for (int i = childCount - 1; i >= 0; i--) {
+ TaskView tv = (TaskView) getChildAt(i);
+ tv.prepareEnterRecentsAnimation((i == (getChildCount() - 1)), offsetTopAlign,
+ offscreenY, mTaskRect);
+ }
+
// If the enter animation started already and we haven't completed a layout yet, do the
// enter animation now
if (mStartEnterAnimationRequestedAfterLayout) {
- startOnEnterAnimation();
+ startEnterRecentsAnimation(mStartEnterAnimationContext);
+ mStartEnterAnimationRequestedAfterLayout = false;
+ mStartEnterAnimationContext = null;
+ }
+
+ // Update the focused task index to be the next item to the top task
+ if (mConfig.launchedWithAltTab) {
+ focusTask(Math.max(0, mStack.getTaskCount() - 2), false);
}
}
}
/** Requests this task stacks to start it's enter-recents animation */
- public void startOnEnterAnimation() {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- if (!config.launchedWithThumbnailAnimation) return;
-
+ public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) {
// If we are still waiting to layout, then just defer until then
if (mAwaitingFirstLayout) {
mStartEnterAnimationRequestedAfterLayout = true;
+ mStartEnterAnimationContext = ctx;
return;
}
- // Animate the task bar of the first task view
- TaskView tv = (TaskView) getChildAt(getChildCount() - 1);
- if (tv != null) {
- tv.animateOnEnterRecents();
+ // Animate all the task views into view
+ ctx.taskRect = mTaskRect;
+ ctx.stackRectSansPeek = mStackRectSansPeek;
+ int childCount = getChildCount();
+ for (int i = childCount - 1; i >= 0; i--) {
+ TaskView tv = (TaskView) getChildAt(i);
+ TaskViewTransform transform = getStackTransform(mStack.indexOfTask(tv.getTask()),
+ getStackScroll());
+ ctx.stackViewIndex = i;
+ ctx.stackViewCount = childCount;
+ ctx.isFrontMost = (i == (getChildCount() - 1));
+ ctx.transform = transform;
+ tv.startEnterRecentsAnimation(ctx);
+ }
+ }
+
+ /** Requests this task stacks to start it's exit-recents animation. */
+ public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
+ // Animate all the task views into view
+ ctx.offscreenTranslationY = mRect.bottom - (mTaskRect.top - mRect.top);
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ TaskView tv = (TaskView) getChildAt(i);
+ tv.startExitToHomeAnimation(ctx);
}
}
@@ -814,6 +897,15 @@
return isTransformedTouchPointInView(x, y, child, null);
}
+ /** Pokes the dozer on user interaction. */
+ void onUserInteraction() {
+ // If the dozer is not running, then either we have not yet laid out, or it has already
+ // fallen asleep, so just let it rest.
+ if (mDozeTrigger.isDozing()) {
+ mDozeTrigger.poke();
+ }
+ }
+
/**** TaskStackCallbacks Implementation ****/
@Override
@@ -863,8 +955,7 @@
ArrayList<TaskViewTransform> curTaskTransforms,
ArrayList<Task> tasks, ArrayList<TaskViewTransform> taskTransforms,
HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut,
- ArrayList<TaskView> childrenToRemoveOut,
- RecentsConfiguration config) {
+ ArrayList<TaskView> childrenToRemoveOut) {
// Animate all of the existing views out of view (if they are not in the visible range in
// the new stack) or to their final positions in the new stack
int movement = 0;
@@ -894,7 +985,7 @@
childViewTransformsOut.put(tv, new Pair(0, toTransform));
}
return Utilities.calculateTranslationAnimationDuration(movement,
- config.filteringCurrentViewsMinAnimDuration);
+ mConfig.filteringCurrentViewsMinAnimDuration);
}
/**
@@ -903,8 +994,7 @@
*/
int getEnterTransformsForFilterAnimation(ArrayList<Task> tasks,
ArrayList<TaskViewTransform> taskTransforms,
- HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut,
- RecentsConfiguration config) {
+ HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransformsOut) {
int offset = 0;
int movement = 0;
int taskCount = tasks.size();
@@ -920,7 +1010,7 @@
// Compose a new transform to fade and slide the new task in
TaskViewTransform fromTransform = new TaskViewTransform(toTransform);
tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
- tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
+ tv.updateViewPropertiesToTaskTransform(fromTransform, 0);
int startDelay = offset *
Constants.Values.TaskStackView.FilterStartDelay;
@@ -934,7 +1024,7 @@
}
}
return Utilities.calculateTranslationAnimationDuration(movement,
- config.filteringNewViewsMinAnimDuration);
+ mConfig.filteringNewViewsMinAnimDuration);
}
/** Orchestrates the animations of the current child views and any new views. */
@@ -942,22 +1032,20 @@
ArrayList<TaskViewTransform> curTaskTransforms,
final ArrayList<Task> tasks,
final ArrayList<TaskViewTransform> taskTransforms) {
- final RecentsConfiguration config = RecentsConfiguration.getInstance();
-
// Calculate the transforms to animate out all the existing views if they are not in the
// new visible range (or to their final positions in the stack if they are)
final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>();
final HashMap<TaskView, Pair<Integer, TaskViewTransform>> childViewTransforms =
new HashMap<TaskView, Pair<Integer, TaskViewTransform>>();
int duration = getExitTransformsForFilterAnimation(curTasks, curTaskTransforms, tasks,
- taskTransforms, childViewTransforms, childrenToRemove, config);
+ taskTransforms, childViewTransforms, childrenToRemove);
// If all the current views are in the visible range of the new stack, then don't wait for
// views to animate out and animate all the new views into their place
final boolean unifyNewViewAnimation = childrenToRemove.isEmpty();
if (unifyNewViewAnimation) {
int inDuration = getEnterTransformsForFilterAnimation(tasks, taskTransforms,
- childViewTransforms, config);
+ childViewTransforms);
duration = Math.max(duration, inDuration);
}
@@ -981,17 +1069,17 @@
// For views that are not already visible, animate them in
childViewTransforms.clear();
int duration = getEnterTransformsForFilterAnimation(tasks,
- taskTransforms, childViewTransforms, config);
+ taskTransforms, childViewTransforms);
for (final TaskView tv : childViewTransforms.keySet()) {
Pair<Integer, TaskViewTransform> t = childViewTransforms.get(tv);
tv.animate().setStartDelay(t.first);
- tv.updateViewPropertiesToTaskTransform(null, t.second, duration);
+ tv.updateViewPropertiesToTaskTransform(t.second, duration);
}
}
}
}
});
- tv.updateViewPropertiesToTaskTransform(null, t.second, duration);
+ tv.updateViewPropertiesToTaskTransform(t.second, duration);
}
}
@@ -1103,6 +1191,11 @@
// but just in case, re-enable it here
tv.setClipViewInStack(true);
+ // If the doze trigger has already fired, then update the state for this task view
+ if (mDozeTrigger.hasTriggered()) {
+ tv.setNoUserInteractionState();
+ }
+
// Add/attach the view to the hierarchy
if (Console.Enabled) {
Console.log(Constants.Log.ViewPool.PoolCallbacks, " [TaskStackView|insertIndex]",
@@ -1119,7 +1212,7 @@
}
// Enable hw layers on this view if hw layers are enabled on the stack
- if (mHwLayersRefCount > 0) {
+ if (mHwLayersTrigger.getCount() > 0) {
tv.enableHwLayers();
}
}
@@ -1188,7 +1281,6 @@
@Override
public void onComponentRemoved(Set<ComponentName> cns) {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
// For other tasks, just remove them directly if they no longer exist
ArrayList<Task> tasks = mStack.getTasks();
for (int i = tasks.size() - 1; i >= 0; i--) {
@@ -1197,7 +1289,7 @@
TaskView tv = getChildViewForTask(t);
if (tv != null) {
// For visible children, defer removing the task until after the animation
- tv.animateRemoval(new Runnable() {
+ tv.startDeleteTaskAnimation(new Runnable() {
@Override
public void run() {
mStack.removeTask(t);
@@ -1494,7 +1586,7 @@
mSv.mMinScroll, mSv.mMaxScroll,
0, overscrollRange);
// Invalidate to kick off computeScroll
- mSv.invalidate();
+ mSv.invalidate(mSv.mStackRect);
} else if (mSv.isScrollOutOfBounds()) {
// Animate the scroll back into bounds
// XXX: Make this animation a function of the velocity OR distance
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java
index 8a9250a..c2b2094 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskThumbnailView.java
@@ -17,15 +17,23 @@
package com.android.systemui.recents.views;
import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
import android.util.AttributeSet;
+import android.view.View;
import android.widget.ImageView;
import com.android.systemui.recents.model.Task;
/** The task thumbnail view */
public class TaskThumbnailView extends ImageView {
+
Task mTask;
+ // Task bar clipping
+ Rect mClipRect;
+ boolean mClipTaskBar = true;
+
public TaskThumbnailView(Context context) {
this(context, null);
}
@@ -43,14 +51,42 @@
setScaleType(ScaleType.FIT_XY);
}
+ @Override
+ public void draw(Canvas canvas) {
+ if (mClipTaskBar && (mClipRect != null)) {
+ int restoreCount = canvas.save(Canvas.CLIP_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+ canvas.clipRect(mClipRect);
+ super.draw(canvas);
+ canvas.restoreToCount(restoreCount);
+ } else {
+ super.draw(canvas);
+ }
+ }
+
+ /** Updates the clip rect based on the given task bar. */
+ void updateTaskBarClip(View taskBar) {
+ // If mClipTaskBar is unset first, then we don't bother setting mTaskBar
+ if (mClipTaskBar) {
+ int top = (int) Math.max(0, taskBar.getTranslationY() +
+ taskBar.getMeasuredHeight() - 1);
+ mClipRect = new Rect(0, top, getMeasuredWidth(), getMeasuredHeight());
+ invalidate(0, 0, taskBar.getMeasuredWidth(), taskBar.getMeasuredHeight() + 1);
+ }
+ }
+
+ /** Disables the task bar clipping. */
+ void disableClipTaskBarView() {
+ mClipTaskBar = false;
+ if (mClipRect != null) {
+ invalidate(0, 0, mClipRect.width(), mClipRect.top);
+ }
+ }
+
/** Binds the thumbnail view to the task */
void rebindToTask(Task t, boolean animate) {
mTask = t;
if (t.thumbnail != null) {
setImageBitmap(t.thumbnail);
- if (animate) {
- // XXX: Investigate how expensive it will be to create a second bitmap and crossfade
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 632c816..09dc1c8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -16,6 +16,7 @@
package com.android.systemui.recents.views;
+import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.content.Context;
@@ -28,9 +29,11 @@
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewPropertyAnimator;
import android.view.animation.AccelerateInterpolator;
import android.widget.FrameLayout;
import com.android.systemui.R;
+import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.model.Task;
@@ -45,10 +48,10 @@
public void onTaskAppInfoClicked(TaskView tv);
public void onTaskFocused(TaskView tv);
public void onTaskDismissed(TaskView tv);
-
- // public void onTaskViewReboundToTask(TaskView tv, Task t);
}
+ RecentsConfiguration mConfig;
+
int mDim;
int mMaxDim;
TimeInterpolator mDimInterpolator = new AccelerateInterpolator();
@@ -59,11 +62,33 @@
boolean mClipViewInStack;
Point mLastTouchDown = new Point();
Path mRoundedRectClipPath = new Path();
+ Rect mTmpRect = new Rect();
TaskThumbnailView mThumbnailView;
TaskBarView mBarView;
TaskViewCallbacks mCb;
+ // Optimizations
+ ValueAnimator.AnimatorUpdateListener mUpdateDimListener =
+ new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ updateDimOverlayFromScale();
+ }
+ };
+ Runnable mEnableThumbnailClip = new Runnable() {
+ @Override
+ public void run() {
+ mThumbnailView.updateTaskBarClip(mBarView);
+ }
+ };
+ Runnable mDisableThumbnailClip = new Runnable() {
+ @Override
+ public void run() {
+ mThumbnailView.disableClipTaskBarView();
+ }
+ };
+
public TaskView(Context context) {
this(context, null);
@@ -79,20 +104,21 @@
public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ mConfig = RecentsConfiguration.getInstance();
setWillNotDraw(false);
+ setDim(getDim());
}
@Override
protected void onFinishInflate() {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- mMaxDim = config.taskStackMaxDim;
+ mMaxDim = mConfig.taskStackMaxDim;
// By default, all views are clipped to other views in their stack
mClipViewInStack = true;
// Bind the views
- mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
+ mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
if (mTaskDataLoaded) {
onTaskDataLoaded(false);
@@ -104,8 +130,7 @@
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Update the rounded rect clip path
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- float radius = config.taskViewRoundedCornerRadiusPx;
+ float radius = mConfig.taskViewRoundedCornerRadiusPx;
mRoundedRectClipPath.reset();
mRoundedRectClipPath.addRoundRect(new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight()),
radius, radius, Path.Direction.CW);
@@ -113,7 +138,7 @@
// Update the outline
Outline o = new Outline();
o.setRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight() -
- config.taskViewShadowOutlineBottomInsetPx, radius);
+ mConfig.taskViewShadowOutlineBottomInsetPx, radius);
setOutline(o);
}
@@ -139,54 +164,64 @@
}
/** Synchronizes this view's properties with the task's transform */
- void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
- TaskViewTransform toTransform, int duration) {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- int minZ = config.taskViewTranslationZMinPx;
- int incZ = config.taskViewTranslationZIncrementPx;
+ void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration) {
+ if (Console.Enabled) {
+ Console.log(Constants.Log.UI.Draw, "[TaskView|updateViewPropertiesToTaskTransform]",
+ "duration: " + duration, Console.AnsiPurple);
+ }
// Update the bar view
- mBarView.updateViewPropertiesToTaskTransform(animateFromTransform, toTransform, duration);
+ mBarView.updateViewPropertiesToTaskTransform(toTransform, duration);
- // Update this task view
+ // Check to see if any properties have changed, and update the task view
if (duration > 0) {
- if (animateFromTransform != null) {
- setTranslationY(animateFromTransform.translationY);
- if (Constants.DebugFlags.App.EnableShadows) {
- setTranslationZ(Math.max(minZ, minZ + (animateFromTransform.t * incZ)));
- }
- setScaleX(animateFromTransform.scale);
- setScaleY(animateFromTransform.scale);
- setAlpha(animateFromTransform.alpha);
+ ViewPropertyAnimator anim = animate();
+ boolean useLayers = false;
+
+ // Animate to the final state
+ if (toTransform.hasTranslationYChangedFrom(getTranslationY())) {
+ anim.translationY(toTransform.translationY);
}
- if (Constants.DebugFlags.App.EnableShadows) {
- animate().translationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
+ if (Constants.DebugFlags.App.EnableShadows &&
+ toTransform.hasTranslationZChangedFrom(getTranslationZ())) {
+ anim.translationZ(toTransform.translationZ);
}
- animate().translationY(toTransform.translationY)
- .scaleX(toTransform.scale)
+ if (toTransform.hasScaleChangedFrom(getScaleX())) {
+ anim.scaleX(toTransform.scale)
.scaleY(toTransform.scale)
- .alpha(toTransform.alpha)
- .setDuration(duration)
- .setInterpolator(config.fastOutSlowInInterpolator)
- .withLayer()
- .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- updateDimOverlayFromScale();
- }
- })
- .start();
- } else {
- setTranslationY(toTransform.translationY);
- if (Constants.DebugFlags.App.EnableShadows) {
- setTranslationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
+ .setUpdateListener(mUpdateDimListener);
+ useLayers = true;
}
- setScaleX(toTransform.scale);
- setScaleY(toTransform.scale);
- setAlpha(toTransform.alpha);
+ if (toTransform.hasAlphaChangedFrom(getAlpha())) {
+ // Use layers if we animate alpha
+ anim.alpha(toTransform.alpha);
+ useLayers = true;
+ }
+ if (useLayers) {
+ anim.withLayer();
+ }
+ anim.setStartDelay(0)
+ .setDuration(duration)
+ .setInterpolator(mConfig.fastOutSlowInInterpolator)
+ .start();
+ } else {
+ // Set the changed properties
+ if (toTransform.hasTranslationYChangedFrom(getTranslationY())) {
+ setTranslationY(toTransform.translationY);
+ }
+ if (Constants.DebugFlags.App.EnableShadows &&
+ toTransform.hasTranslationZChangedFrom(getTranslationZ())) {
+ setTranslationZ(toTransform.translationZ);
+ }
+ if (toTransform.hasScaleChangedFrom(getScaleX())) {
+ setScaleX(toTransform.scale);
+ setScaleY(toTransform.scale);
+ updateDimOverlayFromScale();
+ }
+ if (toTransform.hasAlphaChangedFrom(getAlpha())) {
+ setAlpha(toTransform.alpha);
+ }
}
- updateDimOverlayFromScale();
- invalidate();
}
/** Resets this view's properties */
@@ -199,6 +234,7 @@
setScaleX(1f);
setScaleY(1f);
setAlpha(1f);
+ setDim(0);
invalidate();
}
@@ -223,64 +259,174 @@
/** Prepares this task view for the enter-recents animations. This is called earlier in the
* first layout because the actual animation into recents may take a long time. */
- public void prepareAnimateOnEnterRecents() {
- mBarView.setVisibility(View.INVISIBLE);
+ public void prepareEnterRecentsAnimation(boolean isTaskViewFrontMost, int offsetY, int offscreenY,
+ Rect taskRect) {
+ if (mConfig.launchedFromAppWithScreenshot) {
+ if (isTaskViewFrontMost) {
+ // Hide the task view as we are going to animate the full screenshot into view
+ // and then replace it with this view once we are done
+ setVisibility(View.INVISIBLE);
+ // Also hide the front most task bar view so we can animate it in
+ mBarView.prepareEnterRecentsAnimation();
+ } else {
+ // Top align the task views
+ setTranslationY(offsetY);
+ setScaleX(1f);
+ setScaleY(1f);
+ }
+
+ } else if (mConfig.launchedFromAppWithThumbnail) {
+ if (isTaskViewFrontMost) {
+ // Hide the front most task bar view so we can animate it in
+ mBarView.prepareEnterRecentsAnimation();
+ // Set the dim to 0 so we can animate it in
+ setDim(0);
+ }
+
+ } else if (mConfig.launchedFromHome) {
+ // Move the task view off screen (below) so we can animate it in
+ setTranslationY(offscreenY);
+ setTranslationZ(0);
+ setScaleX(1f);
+ setScaleY(1f);
+ }
}
/** Animates this task view as it enters recents */
- public void animateOnEnterRecents() {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- mBarView.setVisibility(View.VISIBLE);
- mBarView.setTranslationY(-mBarView.getMeasuredHeight());
- mBarView.animate()
- .translationY(0)
- .setStartDelay(config.taskBarEnterAnimDelay)
- .setInterpolator(config.fastOutSlowInInterpolator)
- .setDuration(config.taskBarEnterAnimDuration)
+ public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) {
+ TaskViewTransform transform = ctx.transform;
+
+ if (mConfig.launchedFromAppWithScreenshot) {
+ if (ctx.isFrontMost) {
+ // Animate the full screenshot down first, before swapping with this task view
+ ctx.fullScreenshot.animateOnEnterRecents(ctx, new Runnable() {
+ @Override
+ public void run() {
+ // Animate the task bar of the first task view
+ mBarView.startEnterRecentsAnimation(0, mEnableThumbnailClip);
+ setVisibility(View.VISIBLE);
+ }
+ });
+ } else {
+ // Animate the tasks down behind the full screenshot
+ animate()
+ .scaleX(transform.scale)
+ .scaleY(transform.scale)
+ .translationY(transform.translationY)
+ .setStartDelay(0)
+ .setUpdateListener(null)
+ .setInterpolator(mConfig.linearOutSlowInInterpolator)
+ .setDuration(475)
+ .withLayer()
+ .withEndAction(mEnableThumbnailClip)
+ .start();
+ }
+
+ } else if (mConfig.launchedFromAppWithThumbnail) {
+ if (ctx.isFrontMost) {
+ // Animate the task bar of the first task view
+ mBarView.startEnterRecentsAnimation(mConfig.taskBarEnterAnimDelay, mEnableThumbnailClip);
+
+ // Animate the dim into view as well
+ ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", getDimOverlayFromScale());
+ anim.setStartDelay(mConfig.taskBarEnterAnimDelay);
+ anim.setDuration(mConfig.taskBarEnterAnimDuration);
+ anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
+ anim.start();
+ } else {
+ mEnableThumbnailClip.run();
+ }
+
+ } else if (mConfig.launchedFromHome) {
+ // Animate the tasks up
+ int frontIndex = (ctx.stackViewCount - ctx.stackViewIndex - 1);
+ int delay = mConfig.taskBarEnterAnimDelay +
+ frontIndex * mConfig.taskViewEnterFromHomeDelay;
+ animate()
+ .scaleX(transform.scale)
+ .scaleY(transform.scale)
+ .translationY(transform.translationY)
+ .translationZ(transform.translationZ)
+ .setStartDelay(delay)
+ .setUpdateListener(null)
+ .setInterpolator(mConfig.quintOutInterpolator)
+ .setDuration(mConfig.taskViewEnterFromHomeDuration)
+ .withLayer()
+ .withEndAction(mEnableThumbnailClip)
+ .start();
+ }
+ }
+
+ /** Animates this task view as it leaves recents by pressing home. */
+ public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
+ animate()
+ .translationY(ctx.offscreenTranslationY)
+ .setStartDelay(0)
+ .setUpdateListener(null)
+ .setInterpolator(mConfig.fastOutLinearInInterpolator)
+ .setDuration(mConfig.taskViewExitToHomeDuration)
.withLayer()
+ .withEndAction(ctx.postAnimationTrigger.decrementAsRunnable())
.start();
+ ctx.postAnimationTrigger.increment();
}
/** Animates this task view as it exits recents */
- public void animateOnLeavingRecents(final Runnable r) {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- mBarView.animate()
- .translationY(-mBarView.getMeasuredHeight())
+ public void startLaunchTaskAnimation(final Runnable r, boolean isLaunchingTask) {
+ if (isLaunchingTask) {
+ // Disable the thumbnail clip and animate the bar out
+ mBarView.startLaunchTaskAnimation(mDisableThumbnailClip, r);
+
+ // Animate the dim
+ if (mDim > 0) {
+ ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0);
+ anim.setDuration(mConfig.taskBarExitAnimDuration);
+ anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
+ anim.start();
+ }
+ } else {
+ // Hide the dismiss button
+ mBarView.startLaunchTaskDismissAnimation();
+ }
+ }
+
+ /** Animates the deletion of this task view */
+ public void startDeleteTaskAnimation(final Runnable r) {
+ // Disabling clipping with the stack while the view is animating away
+ setClipViewInStack(false);
+
+ animate().translationX(mConfig.taskViewRemoveAnimTranslationXPx)
+ .alpha(0f)
.setStartDelay(0)
- .setInterpolator(config.fastOutLinearInInterpolator)
- .setDuration(config.taskBarExitAnimDuration)
+ .setUpdateListener(null)
+ .setInterpolator(mConfig.fastOutSlowInInterpolator)
+ .setDuration(mConfig.taskViewRemoveAnimDuration)
.withLayer()
.withEndAction(new Runnable() {
@Override
public void run() {
- post(r);
+ // We just throw this into a runnable because starting a view property
+ // animation using layers can cause inconsisten results if we try and
+ // update the layers while the animation is running. In some cases,
+ // the runnabled passed in may start an animation which also uses layers
+ // so we defer all this by posting this.
+ r.run();
+
+ // Re-enable clipping with the stack (we will reuse this view)
+ setClipViewInStack(true);
}
})
.start();
}
- /** Animates the deletion of this task view */
- public void animateRemoval(final Runnable r) {
- // Disabling clipping with the stack while the view is animating away
- setClipViewInStack(false);
+ /** Animates this task view if the user does not interact with the stack after a certain time. */
+ public void startNoUserInteractionAnimation() {
+ mBarView.startNoUserInteractionAnimation();
+ }
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- animate().translationX(config.taskViewRemoveAnimTranslationXPx)
- .alpha(0f)
- .setStartDelay(0)
- .setInterpolator(config.fastOutSlowInInterpolator)
- .setDuration(config.taskViewRemoveAnimDuration)
- .withLayer()
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- post(r);
-
- // Re-enable clipping with the stack (we will reuse this view)
- setClipViewInStack(false);
- }
- })
- .start();
+ /** Mark this task view that the user does has not interacted with the stack after a certain time. */
+ public void setNoUserInteractionState() {
+ mBarView.setNoUserInteractionState();
}
/** Returns the rect we want to clip (it may not be the full rect) */
@@ -295,11 +441,13 @@
/** Enable the hw layers on this task view */
void enableHwLayers() {
mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ mBarView.enableHwLayers();
}
/** Disable the hw layers on this task view */
void disableHwLayers() {
mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, null);
+ mBarView.disableHwLayers();
}
/**
@@ -307,7 +455,7 @@
* view.
*/
boolean shouldClipViewInStack() {
- return mClipViewInStack;
+ return mClipViewInStack && (getVisibility() == View.VISIBLE);
}
/** Sets whether this view should be clipped, or clipped against. */
@@ -315,28 +463,44 @@
if (clip != mClipViewInStack) {
mClipViewInStack = clip;
if (getParent() instanceof View) {
- Rect r = new Rect();
- getHitRect(r);
- ((View) getParent()).invalidate(r);
+ getHitRect(mTmpRect);
+ ((View) getParent()).invalidate(mTmpRect);
}
}
}
- /** Update the dim as a function of the scale of this view. */
- void updateDimOverlayFromScale() {
+ /** Returns the current dim. */
+ public void setDim(int dim) {
+ mDim = dim;
+ postInvalidateOnAnimation();
+ }
+
+ /** Returns the current dim. */
+ public int getDim() {
+ return mDim;
+ }
+
+ /** Compute the dim as a function of the scale of this view. */
+ int getDimOverlayFromScale() {
float minScale = Constants.Values.TaskStackView.StackPeekMinScale;
float scaleRange = 1f - minScale;
float dim = (1f - getScaleX()) / scaleRange;
dim = mDimInterpolator.getInterpolation(Math.min(dim, 1f));
- mDim = Math.max(0, Math.min(mMaxDim, (int) (dim * 255)));
+ return Math.max(0, Math.min(mMaxDim, (int) (dim * 255)));
+ }
+
+ /** Update the dim as a function of the scale of this view. */
+ void updateDimOverlayFromScale() {
+ setDim(getDimOverlayFromScale());
}
@Override
public void draw(Canvas canvas) {
+ int restoreCount = canvas.save(Canvas.CLIP_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
// Apply the rounded rect clip path on the whole view
canvas.clipPath(mRoundedRectClipPath);
-
super.draw(canvas);
+ canvas.restoreToCount(restoreCount);
// Apply the dim if necessary
if (mDim > 0) {
@@ -393,8 +557,7 @@
mBarView.mApplicationIcon.setOnClickListener(this);
mBarView.mDismissButton.setOnClickListener(this);
if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) {
- RecentsConfiguration config = RecentsConfiguration.getInstance();
- if (config.developerOptionsEnabled) {
+ if (mConfig.developerOptionsEnabled) {
mBarView.mApplicationIcon.setOnLongClickListener(this);
}
}
@@ -426,7 +589,7 @@
} else if (v == mBarView.mDismissButton) {
// Animate out the view and call the callback
final TaskView tv = this;
- animateRemoval(new Runnable() {
+ startDeleteTaskAnimation(new Runnable() {
@Override
public void run() {
mCb.onTaskDismissed(tv);
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 e6391a8..6c420e1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -22,6 +22,7 @@
/* The transform state for a task view */
public class TaskViewTransform {
public int translationY = 0;
+ public int translationZ = 0;
public float scale = 1f;
public float alpha = 1f;
public float dismissAlpha = 1f;
@@ -35,6 +36,7 @@
public TaskViewTransform(TaskViewTransform o) {
translationY = o.translationY;
+ translationZ = o.translationZ;
scale = o.scale;
alpha = o.alpha;
dismissAlpha = o.dismissAlpha;
@@ -43,9 +45,27 @@
t = o.t;
}
+ /** Convenience functions to compare against current property values */
+ public boolean hasAlphaChangedFrom(float v) {
+ return (Float.compare(alpha, v) != 0);
+ }
+ public boolean hasDismissAlphaChangedFrom(float v) {
+ return (Float.compare(dismissAlpha, v) != 0);
+ }
+ public boolean hasScaleChangedFrom(float v) {
+ return (Float.compare(scale, v) != 0);
+ }
+ public boolean hasTranslationYChangedFrom(float v) {
+ return (Float.compare(translationY, v) != 0);
+ }
+ public boolean hasTranslationZChangedFrom(float v) {
+ return (Float.compare(translationZ, v) != 0);
+ }
+
@Override
public String toString() {
- return "TaskViewTransform y: " + translationY + " scale: " + scale + " alpha: " + alpha +
- " visible: " + visible + " rect: " + rect + " dismissAlpha: " + dismissAlpha;
+ return "TaskViewTransform y: " + translationY + " z: " + translationZ + " scale: " + scale +
+ " alpha: " + alpha + " visible: " + visible + " rect: " + rect +
+ " dismissAlpha: " + dismissAlpha;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
new file mode 100644
index 0000000..b5e8ffd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
@@ -0,0 +1,60 @@
+/*
+ * 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.systemui.recents.views;
+
+import android.graphics.Rect;
+import com.android.systemui.recents.ReferenceCountedTrigger;
+
+/* Common code related to view animations */
+public class ViewAnimation {
+
+ /* The animation context for a task view animation into Recents */
+ public static class TaskViewEnterContext {
+ // The full screenshot view that we are animating down
+ FullScreenTransitionView fullScreenshot;
+ // The transform of the current task view
+ TaskViewTransform transform;
+ // The stack rect that the transform is relative to
+ Rect stackRectSansPeek;
+ // The task rect
+ Rect taskRect;
+ // The view index of the current task view
+ int stackViewIndex;
+ // The total number of task views
+ int stackViewCount;
+ // Whether this is the front most task view
+ boolean isFrontMost;
+
+ public TaskViewEnterContext(FullScreenTransitionView fss) {
+ fullScreenshot = fss;
+ }
+ }
+
+ /* The animation context for a task view animation out of Recents */
+ public static class TaskViewExitContext {
+ // A trigger to run some logic when all the animations complete. This works around the fact
+ // that it is difficult to coordinate ViewPropertyAnimators
+ ReferenceCountedTrigger postAnimationTrigger;
+ // The translationY to apply to a TaskView to move it off screen
+ int offscreenTranslationY;
+
+ public TaskViewExitContext(ReferenceCountedTrigger t) {
+ postAnimationTrigger = t;
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index a770f58..80e85f9 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -34,6 +34,7 @@
public class BrightnessController implements ToggleSlider.Listener {
private static final String TAG = "StatusBar.BrightnessController";
+ private static final boolean SHOW_AUTOMATIC_ICON = false;
/**
* {@link android.provider.Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ} uses the range [-1, 1].
@@ -232,7 +233,7 @@
private void updateIcon(boolean automatic) {
if (mIcon != null) {
- mIcon.setImageResource(automatic ?
+ mIcon.setImageResource(automatic && SHOW_AUTOMATIC_ICON ?
com.android.systemui.R.drawable.ic_qs_brightness_auto_on :
com.android.systemui.R.drawable.ic_qs_brightness_auto_off);
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java b/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java
index d67e7cb..a3b10f2 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java
@@ -21,8 +21,16 @@
import android.app.ActivityManagerNative;
import android.content.Context;
import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.UserManager;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
@@ -43,15 +51,18 @@
/**
* A quick and dirty view to show a user switcher.
*/
-public class UserSwitcherHostView extends FrameLayout implements ListView.OnItemClickListener {
+public class UserSwitcherHostView extends FrameLayout
+ implements ListView.OnItemClickListener, View.OnClickListener {
private static final String TAG = "UserSwitcherDialog";
private ArrayList<UserInfo> mUserInfo = new ArrayList<UserInfo>();
+ private UserInfo mGuestUser;
private Adapter mAdapter = new Adapter();
private UserManager mUserManager;
private Runnable mFinishRunnable;
private ListView mListView;
+ private boolean mGuestUserEnabled;
public UserSwitcherHostView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@@ -60,6 +71,9 @@
return;
}
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+
+ mGuestUserEnabled = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.GUEST_USER_ENABLED, 0) == 1;
}
public UserSwitcherHostView(Context context, AttributeSet attrs) {
@@ -80,7 +94,39 @@
@Override
public void onItemClick(AdapterView<?> l, View v, int position, long id) {
- int userId = mAdapter.getItem(position).id;
+ // Last item is the guest
+ if (position == mUserInfo.size()) {
+ postDelayed(new Runnable() {
+ public void run() {
+ switchToGuestUser();
+ }
+ }, 100);
+ } else {
+ final int userId = mAdapter.getItem(position).id;
+ postDelayed(new Runnable() {
+ public void run() {
+ switchUser(userId);
+ }
+ }, 100);
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ // Delete was clicked
+ postDelayed(new Runnable() {
+ public void run() {
+ if (mGuestUser != null) {
+ switchUser(0);
+ mUserManager.removeUser(mGuestUser.id);
+ mGuestUser = null;
+ refreshUsers();
+ }
+ }
+ }, 100);
+ }
+
+ private void switchUser(int userId) {
try {
WindowManagerGlobal.getWindowManagerService().lockNow(null);
ActivityManagerNative.getDefault().switchUser(userId);
@@ -90,6 +136,15 @@
}
}
+ private void switchToGuestUser() {
+ if (mGuestUser == null) {
+ // No guest user. Create one.
+ mGuestUser = mUserManager.createGuest(mContext,
+ mContext.getResources().getString(R.string.guest_nickname));
+ }
+ switchUser(mGuestUser.id);
+ }
+
private void finish() {
if (mFinishRunnable != null) {
mFinishRunnable.run();
@@ -119,9 +174,12 @@
public void refreshUsers() {
mUserInfo.clear();
+ mGuestUser = null;
List<UserInfo> users = mUserManager.getUsers(true);
for (UserInfo user : users) {
- if (!user.isManagedProfile()) {
+ if (user.isGuest()) {
+ mGuestUser = user;
+ } else if (!user.isManagedProfile()) {
mUserInfo.add(user);
}
}
@@ -132,17 +190,25 @@
@Override
public int getCount() {
- return mUserInfo.size();
+ return mUserInfo.size() + (mGuestUserEnabled ? 1 : 0);
}
@Override
public UserInfo getItem(int position) {
- return mUserInfo.get(position);
+ if (position < mUserInfo.size()) {
+ return mUserInfo.get(position);
+ } else {
+ return mGuestUser;
+ }
}
@Override
public long getItemId(int position) {
- return getItem(position).serialNumber;
+ if (position < mUserInfo.size()) {
+ return getItem(position).serialNumber;
+ } else {
+ return mGuestUser != null ? mGuestUser.serialNumber : -1;
+ }
}
@Override
@@ -161,18 +227,46 @@
ViewHolder h = new ViewHolder();
h.name = (TextView) v.findViewById(R.id.user_name);
h.picture = (ImageView) v.findViewById(R.id.user_picture);
+ h.delete = (ImageView) v.findViewById(R.id.user_delete);
v.setTag(h);
return v;
}
private void bindView(ViewHolder h, UserInfo item) {
- h.name.setText(item.name);
- h.picture.setImageBitmap(mUserManager.getUserIcon(item.id));
+ if (item != null) {
+ h.name.setText(item.name);
+ h.picture.setImageBitmap(circularClip(mUserManager.getUserIcon(item.id)));
+ h.delete.setVisibility(item.isGuest() ? View.VISIBLE : View.GONE);
+ h.delete.setOnClickListener(UserSwitcherHostView.this);
+ if (item.isGuest()) {
+ h.picture.setImageResource(R.drawable.ic_account_circle);
+ }
+ } else {
+ h.name.setText(R.string.guest_new_guest);
+ h.picture.setImageResource(R.drawable.ic_account_circle);
+ h.delete.setVisibility(View.GONE);
+ }
+ }
+
+ private Bitmap circularClip(Bitmap input) {
+ if (input == null) {
+ return null;
+ }
+ Bitmap output = Bitmap.createBitmap(input.getWidth(),
+ input.getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(output);
+ final Paint paint = new Paint();
+ paint.setShader(new BitmapShader(input, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
+ paint.setAntiAlias(true);
+ canvas.drawCircle(input.getWidth() / 2, input.getHeight() / 2, input.getWidth() / 2,
+ paint);
+ return output;
}
class ViewHolder {
TextView name;
ImageView picture;
+ ImageView delete;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index f013d13..8d19f50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -90,8 +90,8 @@
private boolean mDimmed;
- private int mBgResId = com.android.internal.R.drawable.notification_quantum_bg;
- private int mDimmedBgResId = com.android.internal.R.drawable.notification_quantum_bg_dim;
+ private int mBgResId = com.android.internal.R.drawable.notification_material_bg;
+ private int mDimmedBgResId = com.android.internal.R.drawable.notification_material_bg_dim;
private int mBgTint = 0;
private int mDimmedBgTint = 0;
@@ -143,7 +143,7 @@
setClipToPadding(false);
mAppearAnimationFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
mRoundedRectCornerRadius = getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_quantum_rounded_rect_radius);
+ com.android.internal.R.dimen.notification_material_rounded_rect_radius);
}
@Override
@@ -158,7 +158,7 @@
private final Runnable mTapTimeoutRunnable = new Runnable() {
@Override
public void run() {
- makeInactive();
+ makeInactive(true /* animate */);
}
};
@@ -183,7 +183,7 @@
break;
case MotionEvent.ACTION_MOVE:
if (!isWithinTouchSlop(event)) {
- makeInactive();
+ makeInactive(true /* animate */);
return false;
}
break;
@@ -193,14 +193,17 @@
makeActive();
postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
} else {
- performClick();
+ boolean performed = performClick();
+ if (performed) {
+ removeCallbacks(mTapTimeoutRunnable);
+ }
}
} else {
- makeInactive();
+ makeInactive(true /* animate */);
}
break;
case MotionEvent.ACTION_CANCEL:
- makeInactive();
+ makeInactive(true /* animate */);
break;
default:
break;
@@ -257,10 +260,14 @@
/**
* Cancels the hotspot and makes the notification inactive.
*/
- private void makeInactive() {
+ public void makeInactive(boolean animate) {
if (mActivated) {
if (mDimmed) {
- startActivateAnimation(true /* reverse */);
+ if (animate) {
+ startActivateAnimation(true /* reverse */);
+ } else {
+ mBackgroundNormal.setVisibility(View.INVISIBLE);
+ }
}
mActivated = false;
}
@@ -351,6 +358,7 @@
mBackgroundDimmed.setVisibility(View.INVISIBLE);
mBackgroundNormal.setVisibility(View.VISIBLE);
mBackgroundNormal.setAlpha(1f);
+ removeCallbacks(mTapTimeoutRunnable);
}
}
@@ -581,7 +589,7 @@
}
public interface OnActivatedListener {
- void onActivated(View view);
- void onActivationReset(View view);
+ void onActivated(ActivatableNotificationView view);
+ void onActivationReset(ActivatableNotificationView view);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index d1484e1..20684a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -48,7 +48,7 @@
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;
@@ -80,17 +80,17 @@
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
+import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
import java.util.Locale;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
public abstract class BaseStatusBar extends SystemUI implements
- CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener {
+ CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
+ RecentsComponent.Callbacks {
public static final String TAG = "StatusBar";
public static final boolean DEBUG = false;
public static final boolean MULTIUSER_DEBUG = false;
@@ -106,6 +106,7 @@
protected static final int MSG_SHOW_HEADS_UP = 1026;
protected static final int MSG_HIDE_HEADS_UP = 1027;
protected static final int MSG_ESCALATE_HEADS_UP = 1028;
+ protected static final int MSG_DECAY_HEADS_UP = 1029;
protected static final boolean ENABLE_HEADS_UP = true;
// scores above this threshold should be displayed in heads up mode.
@@ -129,8 +130,9 @@
protected NotificationData mNotificationData = new NotificationData();
protected NotificationStackScrollLayout mStackScroller;
- protected NotificationData.Entry mInterruptingNotificationEntry;
- protected long mInterruptingNotificationTime;
+ // for heads up notifications
+ protected HeadsUpNotificationView mHeadsUpNotificationView;
+ protected int mHeadsUpNotificationDecay;
// used to notify status bar for suppressing notification LED
protected boolean mPanelSlightlyVisible;
@@ -291,7 +293,7 @@
public void onListenerConnected() {
if (DEBUG) Log.d(TAG, "onListenerConnected");
final StatusBarNotification[] notifications = getActiveNotifications();
- final Ranking currentRanking = getCurrentRanking();
+ final RankingMap currentRanking = getCurrentRanking();
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -303,41 +305,41 @@
}
@Override
- public void onNotificationPosted(final StatusBarNotification sbn) {
+ public void onNotificationPosted(final StatusBarNotification sbn,
+ final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
- final Ranking currentRanking = getCurrentRanking();
mHandler.post(new Runnable() {
@Override
public void run() {
- if (mNotificationData.findByKey(sbn.getKey()) != null) {
- updateNotificationInternal(sbn, currentRanking);
+ if (mNotificationData.findByKey(sbn.getKey()) != null ||
+ isHeadsUp(sbn.getKey())) {
+ updateNotificationInternal(sbn, rankingMap);
} else {
- addNotificationInternal(sbn, currentRanking);
+ addNotificationInternal(sbn, rankingMap);
}
}
});
}
@Override
- public void onNotificationRemoved(final StatusBarNotification sbn) {
+ public void onNotificationRemoved(final StatusBarNotification sbn,
+ final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
- final Ranking currentRanking = getCurrentRanking();
mHandler.post(new Runnable() {
@Override
public void run() {
- removeNotificationInternal(sbn.getKey(), currentRanking);
+ removeNotificationInternal(sbn.getKey(), rankingMap);
}
});
}
@Override
- public void onNotificationRankingUpdate() {
+ public void onNotificationRankingUpdate(final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onRankingUpdate");
- final Ranking currentRanking = getCurrentRanking();
mHandler.post(new Runnable() {
@Override
public void run() {
- updateRankingInternal(currentRanking);
+ updateRankingInternal(rankingMap);
}
});
}
@@ -384,6 +386,7 @@
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mRecents = getComponent(RecentsComponent.class);
+ mRecents.setCallback(this);
mLocale = mContext.getResources().getConfiguration().locale;
mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
@@ -466,6 +469,10 @@
// should be overridden
}
+ public boolean isHeadsUp(String key) {
+ return mHeadsUpNotificationView != null && mHeadsUpNotificationView.isShowing(key);
+ }
+
public boolean notificationIsForCurrentProfiles(StatusBarNotification n) {
final int thisUserId = mCurrentUserId;
final int notificationUserId = n.getUserId();
@@ -505,8 +512,8 @@
protected View updateNotificationVetoButton(View row, StatusBarNotification n) {
View vetoButton = row.findViewById(R.id.veto);
- if (n.isClearable() || (mInterruptingNotificationEntry != null
- && mInterruptingNotificationEntry.row == row)) {
+ if (n.isClearable() || (mHeadsUpNotificationView.getEntry() != null
+ && mHeadsUpNotificationView.getEntry().row == row)) {
final String _pkg = n.getPackageName();
final String _tag = n.getTag();
final int _id = n.getId();
@@ -545,21 +552,20 @@
if (entry.expanded.getId() != com.android.internal.R.id.status_bar_latest_event_content) {
// Using custom RemoteViews
- if (version > 0 && version < Build.VERSION_CODES.GINGERBREAD) {
- entry.row.setBackgroundResource(R.drawable.notification_row_legacy_bg);
- } else if (version < Build.VERSION_CODES.L) {
+ if (version >= Build.VERSION_CODES.GINGERBREAD && version < Build.VERSION_CODES.L) {
entry.row.setBackgroundResourceIds(
com.android.internal.R.drawable.notification_bg,
com.android.internal.R.drawable.notification_bg_dim);
+ entry.legacy = true;
}
} else {
// Using platform templates
final int color = sbn.getNotification().color;
if (isMediaNotification(entry)) {
entry.row.setBackgroundResourceIds(
- com.android.internal.R.drawable.notification_quantum_bg,
+ com.android.internal.R.drawable.notification_material_bg,
color,
- com.android.internal.R.drawable.notification_quantum_bg_dim,
+ com.android.internal.R.drawable.notification_material_bg_dim,
color);
}
}
@@ -764,8 +770,19 @@
}
}
+ @Override
+ public void onVisibilityChanged(boolean visible) {
+ // Do nothing
+ }
+
public abstract void resetHeadsUpDecayTimer();
+ public abstract void scheduleHeadsUpOpen();
+
+ public abstract void scheduleHeadsUpClose();
+
+ public abstract void scheduleHeadsUpEscalation();
+
/**
* Save the current "public" (locked and secure) state of the lockscreen.
*/
@@ -797,6 +814,18 @@
return mUsersAllowingPrivateNotifications.get(userHandle);
}
+ public void onNotificationClear(StatusBarNotification notification) {
+ try {
+ mBarService.onNotificationClear(
+ notification.getPackageName(),
+ notification.getTag(),
+ notification.getId(),
+ notification.getUserId());
+ } catch (android.os.RemoteException ex) {
+ // oh well
+ }
+ }
+
protected class H extends Handler {
public void handleMessage(Message m) {
Intent intent;
@@ -874,10 +903,7 @@
}
public boolean inflateViews(NotificationData.Entry entry, ViewGroup parent, boolean isHeadsUp) {
- int minHeight =
- mContext.getResources().getDimensionPixelSize(R.dimen.notification_min_height);
- int maxHeight =
- mContext.getResources().getDimensionPixelSize(R.dimen.notification_max_height);
+ int maxHeight = mRowMaxHeight;
StatusBarNotification sbn = entry.notification;
RemoteViews contentView = sbn.getNotification().contentView;
RemoteViews bigContentView = sbn.getNotification().bigContentView;
@@ -981,7 +1007,7 @@
if (publicViewLocal == null) {
// Add a basic notification template
publicViewLocal = LayoutInflater.from(mContext).inflate(
- com.android.internal.R.layout.notification_template_quantum_base,
+ com.android.internal.R.layout.notification_template_material_base,
expandedPublic, true);
final TextView title = (TextView) publicViewLocal.findViewById(com.android.internal.R.id.title);
@@ -1026,6 +1052,7 @@
com.android.internal.R.id.text);
text.setText("Unlock your device to see this notification.");
+ entry.autoRedacted = true;
// TODO: fill out "time" as well
}
@@ -1039,7 +1066,7 @@
}
}
entry.row = row;
- entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight);
+ entry.row.setHeightRange(mRowMinHeight, maxHeight);
entry.row.setOnActivatedListener(this);
entry.row.setIsBelowSpeedBump(isBelowSpeedBump(entry.notification));
entry.expanded = contentViewLocal;
@@ -1101,7 +1128,7 @@
try {
if (mIsHeadsUp) {
- mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
+ mHeadsUpNotificationView.clear();
}
mBarService.onNotificationClick(mNotificationKey);
} catch (RemoteException ex) {
@@ -1157,7 +1184,7 @@
}
}
- protected StatusBarNotification removeNotificationViews(String key, Ranking ranking) {
+ protected StatusBarNotification removeNotificationViews(String key, RankingMap ranking) {
NotificationData.Entry entry = mNotificationData.remove(key, ranking);
if (entry == null) {
Log.w(TAG, "removeNotification for unknown key: " + key);
@@ -1197,7 +1224,7 @@
return entry;
}
- protected void addNotificationViews(Entry entry, Ranking ranking) {
+ protected void addNotificationViews(Entry entry, RankingMap ranking) {
if (entry == null) {
return;
}
@@ -1206,7 +1233,7 @@
updateNotifications();
}
- private void addNotificationViews(StatusBarNotification notification, Ranking ranking) {
+ private void addNotificationViews(StatusBarNotification notification, RankingMap ranking) {
addNotificationViews(createNotificationViews(notification), ranking);
}
@@ -1292,9 +1319,9 @@
}
public abstract void addNotificationInternal(StatusBarNotification notification,
- Ranking ranking);
+ RankingMap ranking);
- protected abstract void updateRankingInternal(Ranking ranking);
+ protected abstract void updateRankingInternal(RankingMap ranking);
@Override
public void removeNotification(String key) {
@@ -1303,7 +1330,7 @@
}
}
- public abstract void removeNotificationInternal(String key, Ranking ranking);
+ public abstract void removeNotificationInternal(String key, RankingMap ranking);
public void updateNotification(StatusBarNotification notification) {
if (!USE_NOTIFICATION_LISTENER) {
@@ -1311,12 +1338,18 @@
}
}
- public void updateNotificationInternal(StatusBarNotification notification, Ranking ranking) {
+ public void updateNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
- final NotificationData.Entry oldEntry = mNotificationData.findByKey(notification.getKey());
+ final String key = notification.getKey();
+ boolean wasHeadsUp = isHeadsUp(key);
+ NotificationData.Entry oldEntry;
+ if (wasHeadsUp) {
+ oldEntry = mHeadsUpNotificationView.getEntry();
+ } else {
+ oldEntry = mNotificationData.findByKey(key);
+ }
if (oldEntry == null) {
- Log.w(TAG, "updateNotification for unknown key: " + notification.getKey());
return;
}
@@ -1382,61 +1415,99 @@
&& oldPublicContentView.getPackage() != null
&& oldPublicContentView.getPackage().equals(publicContentView.getPackage())
&& oldPublicContentView.getLayoutId() == publicContentView.getLayoutId());
-
-
boolean updateTicker = notification.getNotification().tickerText != null
&& !TextUtils.equals(notification.getNotification().tickerText,
oldEntry.notification.getNotification().tickerText);
+
+ final boolean shouldInterrupt = shouldInterrupt(notification);
+ final boolean alertAgain = alertAgain(oldEntry);
+ boolean updateSuccessful = false;
if (contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged
&& publicUnchanged) {
- if (DEBUG) Log.d(TAG, "reusing notification for key: " + notification.getKey());
+ if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
oldEntry.notification = notification;
try {
- updateNotificationViews(oldEntry, notification);
-
- if (ENABLE_HEADS_UP && mInterruptingNotificationEntry != null
- && oldNotification == mInterruptingNotificationEntry.notification) {
- if (!shouldInterrupt(notification)) {
- if (DEBUG) Log.d(TAG, "no longer interrupts!");
- mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
- } else {
- if (DEBUG) Log.d(TAG, "updating the current heads up:" + notification);
- mInterruptingNotificationEntry.notification = notification;
- updateHeadsUpViews(mInterruptingNotificationEntry, notification);
+ if (oldEntry.icon != null) {
+ // Update the icon
+ final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
+ notification.getUser(),
+ notification.getNotification().icon,
+ notification.getNotification().iconLevel,
+ notification.getNotification().number,
+ notification.getNotification().tickerText);
+ if (!oldEntry.icon.set(ic)) {
+ handleNotificationError(notification, "Couldn't update icon: " + ic);
+ return;
}
}
- // Update the icon.
- final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
- notification.getUser(),
- notification.getNotification().icon, notification.getNotification().iconLevel,
- notification.getNotification().number,
- notification.getNotification().tickerText);
- if (!oldEntry.icon.set(ic)) {
- handleNotificationError(notification, "Couldn't update icon: " + ic);
- return;
+ if (wasHeadsUp) {
+ if (shouldInterrupt) {
+ updateHeadsUpViews(oldEntry, notification);
+ if (alertAgain) {
+ resetHeadsUpDecayTimer();
+ }
+ } else {
+ // we updated the notification above, so release to build a new shade entry
+ mHeadsUpNotificationView.releaseAndClose();
+ return;
+ }
+ } else {
+ if (shouldInterrupt && alertAgain) {
+ removeNotificationViews(key, ranking);
+ addNotificationInternal(notification, ranking); //this will pop the headsup
+ } else {
+ updateNotificationViews(oldEntry, notification);
+ }
}
mNotificationData.updateRanking(ranking);
updateNotifications();
+ updateSuccessful = true;
}
catch (RuntimeException e) {
// It failed to add cleanly. Log, and remove the view from the panel.
Log.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
- removeNotificationViews(notification.getKey(), ranking);
- addNotificationViews(notification, ranking);
}
- } else {
- if (DEBUG) Log.d(TAG, "not reusing notification for key: " + notification.getKey());
- if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
- removeNotificationViews(notification.getKey(), ranking);
- addNotificationViews(notification, ranking); // will also replace the heads up
- final NotificationData.Entry newEntry = mNotificationData.findByKey(
- notification.getKey());
- final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion();
- if (userChangedExpansion) {
- boolean userExpanded = oldEntry.row.isUserExpanded();
- newEntry.row.setUserExpanded(userExpanded);
- newEntry.row.notifyHeightChanged();
+ }
+ if (!updateSuccessful) {
+ if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
+ if (wasHeadsUp) {
+ if (shouldInterrupt) {
+ if (DEBUG) Log.d(TAG, "rebuilding heads up for key: " + key);
+ Entry newEntry = new Entry(notification, null);
+ ViewGroup holder = mHeadsUpNotificationView.getHolder();
+ if (inflateViewsForHeadsUp(newEntry, holder)) {
+ mHeadsUpNotificationView.showNotification(newEntry);
+ if (alertAgain) {
+ resetHeadsUpDecayTimer();
+ }
+ } else {
+ Log.w(TAG, "Couldn't create new updated headsup for package "
+ + contentView.getPackage());
+ }
+ } else {
+ if (DEBUG) Log.d(TAG, "releasing heads up for key: " + key);
+ oldEntry.notification = notification;
+ mHeadsUpNotificationView.releaseAndClose();
+ return;
+ }
+ } else {
+ if (shouldInterrupt && alertAgain) {
+ if (DEBUG) Log.d(TAG, "reposting to invoke heads up for key: " + key);
+ removeNotificationViews(key, ranking);
+ addNotificationInternal(notification, ranking); //this will pop the headsup
+ } else {
+ if (DEBUG) Log.d(TAG, "rebuilding update in place for key: " + key);
+ removeNotificationViews(key, ranking);
+ addNotificationViews(notification, ranking);
+ final NotificationData.Entry newEntry = mNotificationData.findByKey(key);
+ final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion();
+ if (userChangedExpansion) {
+ boolean userExpanded = oldEntry.row.isUserExpanded();
+ newEntry.row.setUserExpanded(userExpanded);
+ newEntry.row.notifyHeightChanged();
+ }
+ }
}
}
@@ -1511,11 +1582,17 @@
}
protected void notifyHeadsUpScreenOn(boolean screenOn) {
- if (!screenOn && mInterruptingNotificationEntry != null) {
- mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
+ if (!screenOn) {
+ scheduleHeadsUpEscalation();
}
}
+ private boolean alertAgain(Entry entry) {
+ final StatusBarNotification sbn = entry.notification;
+ return entry == null || !entry.hasInterrupted()
+ || (sbn.getNotification().flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
+ }
+
protected boolean shouldInterrupt(StatusBarNotification sbn) {
Notification notification = sbn.getNotification();
// some predicates to make the boolean logic legible
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 84005d1..5bad602 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -209,7 +209,7 @@
}
public int getMaxExpandHeight() {
- return mMaxExpandHeight;
+ return mShowingPublic ? mRowMinHeight : mMaxExpandHeight;
}
/**
@@ -221,30 +221,35 @@
@Override
public boolean isContentExpandable() {
- return mPrivateLayout.isContentExpandable();
+ NotificationContentView showingLayout = getShowingLayout();
+ return showingLayout.isContentExpandable();
}
@Override
public void setActualHeight(int height, boolean notifyListeners) {
mPrivateLayout.setActualHeight(height);
+ mPublicLayout.setActualHeight(height);
invalidate();
super.setActualHeight(height, notifyListeners);
}
@Override
public int getMaxHeight() {
- return mPrivateLayout.getMaxHeight();
+ NotificationContentView showingLayout = getShowingLayout();
+ return showingLayout.getMaxHeight();
}
@Override
public int getMinHeight() {
- return mPrivateLayout.getMinHeight();
+ NotificationContentView showingLayout = getShowingLayout();
+ return showingLayout.getMinHeight();
}
@Override
public void setClipTopAmount(int clipTopAmount) {
super.setClipTopAmount(clipTopAmount);
mPrivateLayout.setClipTopAmount(clipTopAmount);
+ mPublicLayout.setClipTopAmount(clipTopAmount);
}
public boolean isBelowSpeedBump() {
@@ -256,6 +261,16 @@
}
public void notifyContentUpdated() {
+ mPublicLayout.notifyContentUpdated();
mPrivateLayout.notifyContentUpdated();
}
+
+ public boolean isShowingLayoutLayouted() {
+ NotificationContentView showingLayout = getShowingLayout();
+ return showingLayout.getWidth() != 0;
+ }
+
+ private NotificationContentView getShowingLayout() {
+ return mShowingPublic ? mPublicLayout : mPrivateLayout;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
index 4233ab8..bfa74fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
@@ -21,6 +21,7 @@
import android.os.Process;
import android.provider.Settings;
import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -58,17 +59,18 @@
updateSyntheticNotification();
}
- public boolean tryIntercept(StatusBarNotification notification, Ranking ranking) {
- if (ranking == null) return false;
+ public boolean tryIntercept(StatusBarNotification notification, RankingMap rankingMap) {
+ if (rankingMap == null) return false;
if (shouldDisplayIntercepted()) return false;
if (mReleased.contains(notification.getKey())) return false;
- if (!ranking.isInterceptedByDoNotDisturb(notification.getKey())) return false;
+ Ranking ranking = rankingMap.getRanking(notification.getKey());
+ if (!ranking.isInterceptedByDoNotDisturb()) return false;
mIntercepted.put(notification.getKey(), notification);
updateSyntheticNotification();
return true;
}
- public void retryIntercepts(Ranking ranking) {
+ public void retryIntercepts(RankingMap ranking) {
if (ranking == null) return;
final int N = mIntercepted.size();
@@ -111,7 +113,7 @@
return;
}
final Notification n = new Notification.Builder(mContext)
- .setSmallIcon(R.drawable.ic_qs_zen_on)
+ .setSmallIcon(R.drawable.ic_notify_zen)
.setContentTitle(mContext.getResources().getQuantityString(
R.plurals.zen_mode_notification_title,
mIntercepted.size(), mIntercepted.size()))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index f9baecb..5cde979 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -106,7 +106,7 @@
private void selectLayout() {
if (mActualHeight <= mSmallHeight || mExpandedChild == null) {
- if (mContractedChild.getVisibility() != View.VISIBLE) {
+ if (mContractedChild != null && mContractedChild.getVisibility() != View.VISIBLE) {
mContractedChild.setVisibility(View.VISIBLE);
}
if (mExpandedChild != null && mExpandedChild.getVisibility() != View.INVISIBLE) {
@@ -116,7 +116,7 @@
if (mExpandedChild.getVisibility() != View.VISIBLE) {
mExpandedChild.setVisibility(View.VISIBLE);
}
- if (mContractedChild.getVisibility() != View.INVISIBLE) {
+ if (mContractedChild != null && mContractedChild.getVisibility() != View.INVISIBLE) {
mContractedChild.setVisibility(View.INVISIBLE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index d829ac0..9921c55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -18,6 +18,7 @@
import android.app.Notification;
import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.view.View;
@@ -40,6 +41,9 @@
public View expandedPublic; // for insecure lockscreens
public View expandedBig;
private boolean interruption;
+ public boolean autoRedacted; // whether the redacted notification was generated by us
+ public boolean legacy; // whether the notification has a legacy, dark background
+
public Entry() {}
public Entry(StatusBarNotification n, StatusBarIconView ic) {
this.key = n.getKey();
@@ -64,15 +68,23 @@
public void setInterruption() {
interruption = true;
}
+
+ public boolean hasInterrupted() {
+ return interruption;
+ }
}
private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
- private Ranking mRanking;
+ private RankingMap mRanking;
private final Comparator<Entry> mRankingComparator = new Comparator<Entry>() {
@Override
public int compare(Entry a, Entry b) {
if (mRanking != null) {
- return mRanking.getRank(a.key) - mRanking.getRank(b.key);
+ Ranking aRanking = mRanking.getRanking(a.key);
+ Ranking bRanking = mRanking.getRanking(b.key);
+ int aRank = aRanking != null ? aRanking.getRank() : -1;
+ int bRank = bRanking != null ? bRanking.getRank() : -1;
+ return aRank - bRank;
}
final StatusBarNotification na = a.notification;
@@ -105,12 +117,12 @@
return null;
}
- public void add(Entry entry, Ranking ranking) {
+ public void add(Entry entry, RankingMap ranking) {
mEntries.add(entry);
updateRankingAndSort(ranking);
}
- public Entry remove(String key, Ranking ranking) {
+ public Entry remove(String key, RankingMap ranking) {
Entry e = findByKey(key);
if (e == null) {
return null;
@@ -120,7 +132,7 @@
return e;
}
- public void updateRanking(Ranking ranking) {
+ public void updateRanking(RankingMap ranking) {
updateRankingAndSort(ranking);
}
@@ -134,12 +146,13 @@
}
}
} else {
- return mRanking.isAmbient(key);
+ Ranking ranking = mRanking.getRanking(key);
+ return ranking != null && ranking.isAmbient();
}
return false;
}
- private void updateRankingAndSort(Ranking ranking) {
+ private void updateRankingAndSort(RankingMap ranking) {
if (ranking != null) {
mRanking = ranking;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
index 6819d9b..ce5ab5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
@@ -65,7 +65,7 @@
}
private void applyColor(Notification notification, StatusBarIconView view) {
- if (notification.color != Notification.COLOR_DEFAULT) {
+ if (notification.color == Notification.COLOR_DEFAULT) {
if (mNotificationColorUtil.isGrayscale(view.getDrawable())) {
view.setColorFilter(mTintColor, PorterDuff.Mode.MULTIPLY);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java
deleted file mode 100644
index 1503072..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java
+++ /dev/null
@@ -1,52 +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.systemui.statusbar;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Outline;
-import android.graphics.Paint;
-import android.util.AttributeSet;
-import android.view.View;
-
-/**
- * An single dot of the {@link com.android.systemui.statusbar.SpeedBumpDotsLayout}
- */
-public class SpeedBumpDotView extends View {
-
- private final Paint mPaint = new Paint();
-
- public SpeedBumpDotView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mPaint.setAntiAlias(true);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- float radius = getWidth() / 2.0f;
- canvas.drawCircle(radius, radius, radius, mPaint);
- }
-
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
-
- public void setColor(int color) {
- mPaint.setColor(color);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java
deleted file mode 100644
index cac6327..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java
+++ /dev/null
@@ -1,80 +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.systemui.statusbar;
-
-import android.content.Context;
-import android.view.View;
-import com.android.systemui.R;
-
-/**
- * The Algorithm of the {@link com.android.systemui.statusbar.SpeedBumpDotsLayout} which can be
- * queried for {@link * com.android.systemui.statusbar.SpeedBumpDotsState}
- */
-public class SpeedBumpDotsAlgorithm {
-
- private final float mDotRadius;
-
- public SpeedBumpDotsAlgorithm(Context context) {
- mDotRadius = context.getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height)
- / 2.0f;
- }
-
- public void getState(SpeedBumpDotsState resultState) {
-
- // First reset the current state and ensure that every View has a ViewState
- resultState.resetViewStates();
-
- SpeedBumpDotsLayout hostView = resultState.getHostView();
- boolean currentlyVisible = hostView.isCurrentlyVisible();
- resultState.setActiveState(currentlyVisible
- ? SpeedBumpDotsState.SHOWN
- : SpeedBumpDotsState.HIDDEN);
- int hostWidth = hostView.getWidth();
- float layoutWidth = hostWidth - 2 * mDotRadius;
- int childCount = hostView.getChildCount();
- float paddingBetween = layoutWidth / (childCount - 1);
- float centerY = hostView.getHeight() / 2.0f;
- for (int i = 0; i < childCount; i++) {
- View child = hostView.getChildAt(i);
- SpeedBumpDotsState.ViewState viewState = resultState.getViewStateForView(child);
- if (currentlyVisible) {
- float xTranslation = i * paddingBetween;
- viewState.xTranslation = xTranslation;
- viewState.yTranslation = calculateYTranslation(hostView, centerY, xTranslation,
- layoutWidth);
- } else {
- viewState.xTranslation = layoutWidth / 2;
- viewState.yTranslation = centerY - mDotRadius;
- }
- viewState.alpha = currentlyVisible ? 1.0f : 0.0f;
- viewState.scale = currentlyVisible ? 1.0f : 0.5f;
- }
- }
-
- private float calculateYTranslation(SpeedBumpDotsLayout hostView, float centerY,
- float xTranslation, float layoutWidth) {
- float t = hostView.getAnimationProgress();
- if (t == 0.0f || t == 1.0f) {
- return centerY - mDotRadius;
- }
- float damping = (0.5f -Math.abs(0.5f - t)) * 1.3f;
- float partialOffset = xTranslation / layoutWidth;
- float indentFactor = (float) (Math.sin((t + partialOffset * 1.5f) * - Math.PI) * damping);
- return (1.0f - indentFactor) * centerY - mDotRadius;
- }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java
deleted file mode 100644
index ddf5215..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java
+++ /dev/null
@@ -1,136 +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.systemui.statusbar;
-
-import android.animation.TimeAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import com.android.systemui.R;
-
-/**
- * A layout with a certain number of dots which are integrated in the
- * {@link com.android.systemui.statusbar.SpeedBumpView}
- */
-public class SpeedBumpDotsLayout extends ViewGroup {
-
- private static final float DOT_CLICK_ANIMATION_LENGTH = 300;
- private final int mDotSize;
- private final SpeedBumpDotsAlgorithm mAlgorithm = new SpeedBumpDotsAlgorithm(getContext());
- private final SpeedBumpDotsState mCurrentState = new SpeedBumpDotsState(this);
- private boolean mIsCurrentlyVisible = true;
- private final ValueAnimator mClickAnimator;
- private float mAnimationProgress;
- private ValueAnimator.AnimatorUpdateListener mClickUpdateListener
- = new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mAnimationProgress = animation.getAnimatedFraction();
- updateChildren();
- }
- };
-
- public SpeedBumpDotsLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- mDotSize = getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height);
- createDots(context, attrs);
- mClickAnimator = TimeAnimator.ofFloat(0, DOT_CLICK_ANIMATION_LENGTH);
- mClickAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
- mClickAnimator.addUpdateListener(mClickUpdateListener);
- }
-
- private void createDots(Context context, AttributeSet attrs) {
- SpeedBumpDotView blueDot = new SpeedBumpDotView(context, attrs);
- blueDot.setColor(getResources().getColor(R.color.speed_bump_dot_blue));
- addView(blueDot);
-
- SpeedBumpDotView redDot = new SpeedBumpDotView(context, attrs);
- redDot.setColor(getResources().getColor(R.color.speed_bump_dot_red));
- addView(redDot);
-
- SpeedBumpDotView yellowDot = new SpeedBumpDotView(context, attrs);
- yellowDot.setColor(getResources().getColor(R.color.speed_bump_dot_yellow));
- addView(yellowDot);
-
- SpeedBumpDotView greenDot = new SpeedBumpDotView(context, attrs);
- greenDot.setColor(getResources().getColor(R.color.speed_bump_dot_green));
- addView(greenDot);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int childWidthSpec = MeasureSpec.makeMeasureSpec(mDotSize,
- MeasureSpec.getMode(widthMeasureSpec));
- int childHeightSpec = MeasureSpec.makeMeasureSpec(mDotSize,
- MeasureSpec.getMode(heightMeasureSpec));
- measureChildren(childWidthSpec, childHeightSpec);
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = getChildAt(i);
- child.layout(0, 0, mDotSize, mDotSize);
- }
- if (changed) {
- updateChildren();
- }
- }
-
- private void updateChildren() {
- mAlgorithm.getState(mCurrentState);
- mCurrentState.apply();
- }
-
- public void performVisibilityAnimation(boolean visible) {
- if (mClickAnimator.isRunning()) {
- mClickAnimator.cancel();
- }
- mIsCurrentlyVisible = visible;
- mAlgorithm.getState(mCurrentState);
- mCurrentState.animateToState();
- }
-
- public void setInvisible() {
- mIsCurrentlyVisible = false;
- mAlgorithm.getState(mCurrentState);
- mCurrentState.apply();
- }
-
- public boolean isCurrentlyVisible() {
- return mIsCurrentlyVisible;
- }
-
- public void performDotClickAnimation() {
- if (mClickAnimator.isRunning()) {
- // don't perform an animation if it's running already
- return;
- }
- mClickAnimator.start();
- }
-
-
- public float getAnimationProgress() {
- return mAnimationProgress;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java
deleted file mode 100644
index 4febab1..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java
+++ /dev/null
@@ -1,128 +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.systemui.statusbar;
-
-import android.view.View;
-import android.view.ViewPropertyAnimator;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A state of a {@link com.android.systemui.statusbar.SpeedBumpDotsLayout}
- */
-public class SpeedBumpDotsState {
-
- public static final int HIDDEN = 1;
- public static final int SHOWN = 2;
- private static final int VISIBILITY_ANIMATION_DELAY_PER_ELEMENT = 80;
-
- private final SpeedBumpDotsLayout mHostView;
- private final HashMap<View, ViewState> mStateMap = new HashMap<View, ViewState>();
- private final Interpolator mFastOutSlowInInterpolator;
- private int mActiveState = 0;
-
- public SpeedBumpDotsState(SpeedBumpDotsLayout hostLayout) {
- mHostView = hostLayout;
- mFastOutSlowInInterpolator = AnimationUtils
- .loadInterpolator(hostLayout.getContext(),
- android.R.interpolator.fast_out_slow_in);
- }
-
- public SpeedBumpDotsLayout getHostView() {
- return mHostView;
- }
-
- public void resetViewStates() {
- int numChildren = mHostView.getChildCount();
- for (int i = 0; i < numChildren; i++) {
- View child = mHostView.getChildAt(i);
- ViewState viewState = mStateMap.get(child);
- if (viewState == null) {
- viewState = new ViewState();
- mStateMap.put(child, viewState);
- }
- }
- }
-
- public ViewState getViewStateForView(View requestedView) {
- return mStateMap.get(requestedView);
- }
-
- public void apply() {
- int childCount = mHostView.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = mHostView.getChildAt(i);
- ViewState viewState = mStateMap.get(child);
-
- child.setTranslationX(viewState.xTranslation);
- child.setTranslationY(viewState.yTranslation);
- child.setScaleX(viewState.scale);
- child.setScaleY(viewState.scale);
- child.setAlpha(viewState.alpha);
- }
- }
-
- public void animateToState() {
- int childCount = mHostView.getChildCount();
- int middleIndex = (childCount - 1) / 2;
- long delayPerElement = VISIBILITY_ANIMATION_DELAY_PER_ELEMENT;
- boolean isAppearing = getActiveState() == SHOWN;
- boolean isDisappearing = getActiveState() == HIDDEN;
- for (int i = 0; i < childCount; i++) {
- int delayIndex;
- if (i <= middleIndex) {
- delayIndex = i * 2;
- } else {
- int distToMiddle = i - middleIndex;
- delayIndex = (childCount - 1) - (distToMiddle - 1) * 2;
- }
- long startDelay = 0;
- if (isAppearing || isDisappearing) {
- if (isDisappearing) {
- delayIndex = childCount - 1 - delayIndex;
- }
- startDelay = delayIndex * delayPerElement;
- }
- View child = mHostView.getChildAt(i);
- ViewState viewState = mStateMap.get(child);
- child.animate().setInterpolator(mFastOutSlowInInterpolator)
- .setStartDelay(startDelay)
- .alpha(viewState.alpha)
- .translationX(viewState.xTranslation)
- .translationY(viewState.yTranslation)
- .scaleX(viewState.scale).scaleY(viewState.scale);
- }
- }
-
- public int getActiveState() {
- return mActiveState;
- }
-
- public void setActiveState(int mActiveState) {
- this.mActiveState = mActiveState;
- }
-
- public static class ViewState {
- float xTranslation;
- float yTranslation;
- float alpha;
- float scale;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
index 689d0e9..f80f0fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
@@ -16,71 +16,26 @@
package com.android.systemui.statusbar;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
import android.content.Context;
-import android.graphics.Outline;
import android.util.AttributeSet;
-import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
-import android.widget.TextView;
import com.android.systemui.R;
/**
* The view representing the separation between important and less important notifications
*/
-public class SpeedBumpView extends ExpandableView implements View.OnClickListener {
+public class SpeedBumpView extends ExpandableView {
- private final int mCollapsedHeight;
- private final int mDotsHeight;
- private final int mTextPaddingInset;
- private SpeedBumpDotsLayout mDots;
- private AlphaOptimizedView mLineLeft;
- private AlphaOptimizedView mLineRight;
- private boolean mIsExpanded;
- private boolean mDividerVisible = true;
- private ValueAnimator mCurrentAnimator;
+ private final int mSpeedBumpHeight;
+ private AlphaOptimizedView mLine;
+ private boolean mIsVisible = true;
private final Interpolator mFastOutSlowInInterpolator;
- private float mCenterX;
- private TextView mExplanationText;
- private boolean mExplanationTextVisible = false;
- private AnimatorListenerAdapter mHideExplanationListener = new AnimatorListenerAdapter() {
- private boolean mCancelled;
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!mCancelled) {
- mExplanationText.setVisibility(View.INVISIBLE);
- }
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancelled = true;
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- mCancelled = false;
- }
- };
- private Animator.AnimatorListener mAnimationFinishedListener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mCurrentAnimator = null;
- }
- };
public SpeedBumpView(Context context, AttributeSet attrs) {
super(context, attrs);
- mCollapsedHeight = getResources()
- .getDimensionPixelSize(R.dimen.speed_bump_height_collapsed);
- mTextPaddingInset = getResources().getDimensionPixelSize(
- R.dimen.speed_bump_text_padding_inset);
- mDotsHeight = getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height);
- setOnClickListener(this);
+ mSpeedBumpHeight = getResources()
+ .getDimensionPixelSize(R.dimen.speed_bump_height);
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
android.R.interpolator.fast_out_slow_in);
}
@@ -88,111 +43,41 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mDots = (SpeedBumpDotsLayout) findViewById(R.id.speed_bump_dots_layout);
- mLineLeft = (AlphaOptimizedView) findViewById(R.id.speedbump_line_left);
- mLineRight = (AlphaOptimizedView) findViewById(R.id.speedbump_line_right);
- mExplanationText = (TextView) findViewById(R.id.speed_bump_text);
- resetExplanationText();
-
+ mLine = (AlphaOptimizedView) findViewById(R.id.speedbump_line);
}
@Override
protected int getInitialHeight() {
- return mCollapsedHeight;
+ return mSpeedBumpHeight;
}
@Override
public int getIntrinsicHeight() {
- if (mCurrentAnimator != null) {
- // expand animation is running
- return getActualHeight();
- }
- return mIsExpanded ? getHeight() : mCollapsedHeight;
+ return mSpeedBumpHeight;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- Outline outline = new Outline();
- mCenterX = getWidth() / 2;
- float centerY = getHeight() / 2;
- // TODO: hide outline better
- // Temporary workaround to hide outline on a transparent view
- int outlineLeft = (int) (mCenterX - getResources().getDisplayMetrics().densityDpi * 8);
- int outlineTop = (int) (centerY - mDotsHeight / 2);
- outline.setOval(outlineLeft, outlineTop, outlineLeft + mDotsHeight,
- outlineTop + mDotsHeight);
- setOutline(outline);
- mLineLeft.setPivotX(mLineLeft.getWidth());
- mLineLeft.setPivotY(mLineLeft.getHeight() / 2);
- mLineRight.setPivotX(0);
- mLineRight.setPivotY(mLineRight.getHeight() / 2);
+ mLine.setPivotX(mLine.getWidth() / 2);
+ mLine.setPivotY(mLine.getHeight() / 2);
+ setOutline(null);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec);
- int height = mCollapsedHeight + mExplanationText.getMeasuredHeight() - mTextPaddingInset;
+ int height = mSpeedBumpHeight;
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
}
@Override
- public void onClick(View v) {
- if (mCurrentAnimator != null) {
- return;
- }
- int startValue = mIsExpanded ? getMaxHeight() : mCollapsedHeight;
- int endValue = mIsExpanded ? mCollapsedHeight : getMaxHeight();
- mCurrentAnimator = ValueAnimator.ofInt(startValue, endValue);
- mCurrentAnimator.setInterpolator(mFastOutSlowInInterpolator);
- mCurrentAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- setActualHeight((int) animation.getAnimatedValue());
- }
- });
- mCurrentAnimator.addListener(mAnimationFinishedListener);
- mCurrentAnimator.start();
- mIsExpanded = !mIsExpanded;
- mDots.performDotClickAnimation();
- animateExplanationTextInternal(mIsExpanded);
- }
-
- private void animateExplanationTextInternal(boolean visible) {
- if (mExplanationTextVisible != visible) {
- float translationY = 0.0f;
- float scale = 0.5f;
- float alpha = 0.0f;
- boolean needsHideListener = true;
- if (visible) {
- mExplanationText.setVisibility(VISIBLE);
- translationY = mDots.getBottom() - mTextPaddingInset;
- scale = 1.0f;
- alpha = 1.0f;
- needsHideListener = false;
- }
- mExplanationText.animate().setInterpolator(mFastOutSlowInInterpolator)
- .alpha(alpha)
- .scaleX(scale)
- .scaleY(scale)
- .translationY(translationY)
- .setListener(needsHideListener ? mHideExplanationListener : null);
- mExplanationTextVisible = visible;
- }
- }
-
- @Override
public boolean isTransparent() {
return true;
}
public void performVisibilityAnimation(boolean nowVisible) {
animateDivider(nowVisible, null /* onFinishedRunnable */);
-
- // Animate explanation Text
- if (mIsExpanded) {
- animateExplanationTextInternal(nowVisible);
- }
}
/**
@@ -203,28 +88,16 @@
* finished.
*/
public void animateDivider(boolean nowVisible, Runnable onFinishedRunnable) {
- if (nowVisible != mDividerVisible) {
+ if (nowVisible != mIsVisible) {
// Animate dividers
float endValue = nowVisible ? 1.0f : 0.0f;
- float endTranslationXLeft = nowVisible ? 0.0f : mCenterX - mLineLeft.getRight();
- float endTranslationXRight = nowVisible ? 0.0f : mCenterX - mLineRight.getLeft();
- mLineLeft.animate()
+ mLine.animate()
.alpha(endValue)
.scaleX(endValue)
.scaleY(endValue)
- .translationX(endTranslationXLeft)
.setInterpolator(mFastOutSlowInInterpolator)
.withEndAction(onFinishedRunnable);
- mLineRight.animate()
- .alpha(endValue)
- .scaleX(endValue)
- .scaleY(endValue)
- .translationX(endTranslationXRight)
- .setInterpolator(mFastOutSlowInInterpolator);
-
- // Animate dots
- mDots.performVisibilityAnimation(nowVisible);
- mDividerVisible = nowVisible;
+ mIsVisible = nowVisible;
} else {
if (onFinishedRunnable != null) {
onFinishedRunnable.run();
@@ -233,34 +106,10 @@
}
public void setInvisible() {
- float endTranslationXLeft = mCenterX - mLineLeft.getRight();
- float endTranslationXRight = mCenterX - mLineRight.getLeft();
- mLineLeft.setAlpha(0.0f);
- mLineLeft.setScaleX(0.0f);
- mLineLeft.setScaleY(0.0f);
- mLineLeft.setTranslationX(endTranslationXLeft);
- mLineRight.setAlpha(0.0f);
- mLineRight.setScaleX(0.0f);
- mLineRight.setScaleY(0.0f);
- mLineRight.setTranslationX(endTranslationXRight);
- mDots.setInvisible();
- resetExplanationText();
-
- mDividerVisible = false;
- }
-
- public void collapse() {
- if (mIsExpanded) {
- setActualHeight(mCollapsedHeight);
- mIsExpanded = false;
- }
- resetExplanationText();
- }
-
- public void animateExplanationText(boolean nowVisible) {
- if (mIsExpanded) {
- animateExplanationTextInternal(nowVisible);
- }
+ mLine.setAlpha(0.0f);
+ mLine.setScaleX(0.0f);
+ mLine.setScaleY(0.0f);
+ mIsVisible = false;
}
@Override
@@ -272,17 +121,4 @@
public void performAddAnimation(long delay) {
performVisibilityAnimation(true);
}
-
- private void resetExplanationText() {
- mExplanationText.setTranslationY(0);
- mExplanationText.setVisibility(INVISIBLE);
- mExplanationText.setAlpha(0.0f);
- mExplanationText.setScaleX(0.5f);
- mExplanationText.setScaleY(0.5f);
- mExplanationTextVisible = false;
- }
-
- public boolean isExpanded() {
- return mIsExpanded;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
index 086a266..e312d58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
@@ -423,6 +423,7 @@
return;
}
if (!animate) {
+ view.animate().cancel();
view.setAlpha(alpha);
view.setScaleX(scale);
view.setScaleY(scale);
@@ -465,6 +466,13 @@
}
public void reset() {
+ if (mSwipeAnimator != null) {
+ mSwipeAnimator.cancel();
+ }
+ ArrayList<View> targetViews = mCallback.getTranslationViews();
+ for (View view : targetViews) {
+ view.animate().cancel();
+ }
setTranslation(0.0f, true);
mSwipingInProgress = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 34179cb..dde95bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -688,6 +688,9 @@
@Override
protected boolean isScrolledToBottom() {
+ if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
+ return true;
+ }
if (!isInSettings()) {
return mNotificationStackScroller.isScrolledToBottom();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 772d0e7..1f3098d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -27,6 +27,7 @@
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import android.view.ViewTreeObserver;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
@@ -67,6 +68,11 @@
private VelocityTrackerInterface mVelocityTracker;
private FlingAnimationUtils mFlingAnimationUtils;
+ /**
+ * Whether an instant expand request is currently pending and we are just waiting for layout.
+ */
+ private boolean mInstantExpanding;
+
PanelBar mBar;
protected int mMaxPanelHeight = -1;
@@ -128,6 +134,9 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
+ if (mInstantExpanding) {
+ return false;
+ }
/*
* We capture touch events here and update the expand height here in case according to
@@ -263,6 +272,9 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
+ if (mInstantExpanding) {
+ return false;
+ }
/*
* If the user drags anywhere inside the panel we intercept it if he moves his finger
@@ -556,6 +568,41 @@
}
}
+ public void instantExpand() {
+ mInstantExpanding = true;
+ abortAnimations();
+ if (mTracking) {
+ onTrackingStopped(true /* expands */); // The panel is expanded after this call.
+ onExpandingFinished();
+ }
+ setVisibility(VISIBLE);
+
+ // Wait for window manager to pickup the change, so we know the maximum height of the panel
+ // then.
+ getViewTreeObserver().addOnGlobalLayoutListener(
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ if (mStatusBar.getStatusBarWindow().getHeight()
+ != mStatusBar.getStatusBarHeight()) {
+ getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ setExpandedFraction(1f);
+ mInstantExpanding = false;
+ }
+ }
+ });
+
+ // Make sure a layout really happens.
+ requestLayout();
+ }
+
+ private void abortAnimations() {
+ cancelPeek();
+ if (mHeightAnimator != null) {
+ mHeightAnimator.cancel();
+ }
+ }
+
protected void startUnlockHintAnimation() {
// We don't need to hint the user if an animation is already running or the user is changing
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index ac9866c..1da7dab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -64,7 +64,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
-import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.DisplayMetrics;
@@ -81,6 +81,7 @@
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewPropertyAnimator;
+import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
@@ -102,6 +103,7 @@
import com.android.systemui.qs.CircularClipper;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper;
@@ -265,7 +267,6 @@
private TextView mCarrierLabel;
private boolean mCarrierLabelVisible = false;
private int mCarrierLabelHeight;
- private TextView mEmergencyCallLabel;
private int mStatusBarHeaderHeight;
private boolean mShowCarrierInPanel = false;
@@ -277,10 +278,6 @@
// the date view
DateView mDateView;
- // for heads up notifications
- private HeadsUpNotificationView mHeadsUpNotificationView;
- private int mHeadsUpNotificationDecay;
-
// on-screen navigation buttons
private NavigationBarView mNavigationBarView = null;
private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
@@ -289,6 +286,7 @@
int mTrackingPosition; // the position of the top of the tracking view.
// ticker
+ private boolean mTickerEnabled;
private Ticker mTicker;
private View mTickerView;
private boolean mTicking;
@@ -365,7 +363,7 @@
if (!mUseHeadsUp) {
Log.d(TAG, "dismissing any existing heads up notification on disable event");
setHeadsUpVisibility(false);
- mHeadsUpNotificationView.setNotification(null);
+ mHeadsUpNotificationView.release();
removeHeadsUpView();
} else {
addHeadsUpView();
@@ -644,7 +642,6 @@
mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
mNotificationIcons.setOverflowIndicator(mMoreIcon);
mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
- mTickerView = mStatusBarView.findViewById(R.id.ticker);
mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
R.id.notification_stack_scroller);
@@ -684,10 +681,17 @@
mDateTimeView.setEnabled(true);
}
- mTicker = new MyTicker(context, mStatusBarView);
+ mTickerEnabled = res.getBoolean(R.bool.enable_ticker);
+ if (mTickerEnabled) {
+ final ViewStub tickerStub = (ViewStub) mStatusBarView.findViewById(R.id.ticker_stub);
+ if (tickerStub != null) {
+ mTickerView = tickerStub.inflate();
+ mTicker = new MyTicker(context, mStatusBarView);
- TickerView tickerView = (TickerView)mStatusBarView.findViewById(R.id.tickerText);
- tickerView.mTicker = mTicker;
+ TickerView tickerView = (TickerView) mStatusBarView.findViewById(R.id.tickerText);
+ tickerView.mTicker = mTicker;
+ }
+ }
mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
@@ -712,23 +716,9 @@
mNetworkController.addSignalCluster(signalCluster);
signalCluster.setNetworkController(mNetworkController);
-
final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
if (isAPhone) {
- mEmergencyCallLabel =
- (TextView) mStatusBarWindow.findViewById(R.id.emergency_calls_only);
- // TODO: Uncomment when correctly positioned
-// if (mEmergencyCallLabel != null) {
-// mNetworkController.addEmergencyLabelView(mEmergencyCallLabel);
-// mEmergencyCallLabel.setOnClickListener(new View.OnClickListener() {
-// public void onClick(View v) { }});
-// mEmergencyCallLabel.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
-// @Override
-// public void onLayoutChange(View v, int left, int top, int right, int bottom,
-// int oldLeft, int oldTop, int oldRight, int oldBottom) {
-// updateCarrierLabelVisibility(false);
-// }});
-// }
+ mNetworkController.addEmergencyLabelView(mHeader);
}
mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label);
@@ -754,6 +744,8 @@
// updateCarrierLabelVisibility(false);
}
+ mBatteryController.setStatusBarHeaderView(mHeader);
+
// Set up the quick settings tile panel
mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
if (mQSPanel != null) {
@@ -823,6 +815,10 @@
return mStatusBarView;
}
+ public StatusBarWindowView getStatusBarWindow() {
+ return mStatusBarWindow;
+ }
+
@Override
protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) {
boolean opaque = false;
@@ -1055,7 +1051,7 @@
}
@Override
- public void addNotificationInternal(StatusBarNotification notification, Ranking ranking) {
+ public void addNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
if (mZenMode != Global.ZEN_MODE_OFF && mIntercepted.tryIntercept(notification, ranking)) {
// Forward the ranking so we can sort the new notification.
@@ -1066,31 +1062,26 @@
displayNotification(notification, ranking);
}
- public void displayNotification(StatusBarNotification notification,
- Ranking ranking) {
- Entry shadeEntry = createNotificationViews(notification);
- if (shadeEntry == null) {
- return;
- }
+ public void displayNotification(StatusBarNotification notification, RankingMap ranking) {
if (mUseHeadsUp && shouldInterrupt(notification)) {
if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
Entry interruptionCandidate = new Entry(notification, null);
ViewGroup holder = mHeadsUpNotificationView.getHolder();
if (inflateViewsForHeadsUp(interruptionCandidate, holder)) {
- mInterruptingNotificationTime = System.currentTimeMillis();
- mInterruptingNotificationEntry = interruptionCandidate;
- shadeEntry.setInterruption();
-
// 1. Populate mHeadsUpNotificationView
- mHeadsUpNotificationView.setNotification(mInterruptingNotificationEntry);
+ mHeadsUpNotificationView.showNotification(interruptionCandidate);
- // 2. Animate mHeadsUpNotificationView in
- mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
-
- // 3. Set alarm to age the notification off
- resetHeadsUpDecayTimer();
+ // do not show the notification in the shade, yet.
+ return;
}
- } else if (notification.getNotification().fullScreenIntent != null) {
+ }
+
+ Entry shadeEntry = createNotificationViews(notification);
+ if (shadeEntry == null) {
+ return;
+ }
+
+ if (notification.getNotification().fullScreenIntent != null) {
// Stop screensaver if the notification has a full-screen intent.
// (like an incoming phone call)
awakenDreams();
@@ -1105,7 +1096,7 @@
// usual case: status bar visible & not immersive
// show the ticker if there isn't already a heads up
- if (mInterruptingNotificationEntry == null) {
+ if (mHeadsUpNotificationView.getEntry() == null) {
tick(notification, true);
}
}
@@ -1115,46 +1106,76 @@
updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
}
+ public void displayNotificationFromHeadsUp(StatusBarNotification notification) {
+ NotificationData.Entry shadeEntry = createNotificationViews(notification);
+ if (shadeEntry == null) {
+ return;
+ }
+ shadeEntry.setInterruption();
+
+ addNotificationViews(shadeEntry, null);
+ // Recalculate the position of the sliding windows and the titles.
+ setAreThereNotifications();
+ updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
+ }
+
@Override
public void resetHeadsUpDecayTimer() {
- mHandler.removeMessages(MSG_HIDE_HEADS_UP);
+ mHandler.removeMessages(MSG_DECAY_HEADS_UP);
if (mUseHeadsUp && mHeadsUpNotificationDecay > 0
&& mHeadsUpNotificationView.isClearable()) {
- mHandler.sendEmptyMessageDelayed(MSG_HIDE_HEADS_UP, mHeadsUpNotificationDecay);
+ mHandler.sendEmptyMessageDelayed(MSG_DECAY_HEADS_UP, mHeadsUpNotificationDecay);
}
}
@Override
- public void updateNotificationInternal(StatusBarNotification notification, Ranking ranking) {
+ public void scheduleHeadsUpOpen() {
+ mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
+ }
+
+ @Override
+ public void scheduleHeadsUpClose() {
+ mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
+ }
+
+ @Override
+ public void scheduleHeadsUpEscalation() {
+ mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
+ }
+
+ @Override
+ public void updateNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
super.updateNotificationInternal(notification, ranking);
// if we're here, then the notification is already in the shade
mIntercepted.remove(notification.getKey());
}
@Override
- protected void updateRankingInternal(Ranking ranking) {
+ protected void updateRankingInternal(RankingMap ranking) {
mNotificationData.updateRanking(ranking);
mIntercepted.retryIntercepts(ranking);
updateNotifications();
}
@Override
- public void removeNotificationInternal(String key, Ranking ranking) {
+ public void removeNotificationInternal(String key, RankingMap ranking) {
+ if (ENABLE_HEADS_UP && mHeadsUpNotificationView.getEntry() != null
+ && key.equals(mHeadsUpNotificationView.getEntry().notification.getKey())) {
+ mHeadsUpNotificationView.clear();
+ }
+
StatusBarNotification old = removeNotificationViews(key, ranking);
if (SPEW) Log.d(TAG, "removeNotification key=" + key + " old=" + old);
if (old != null) {
// Cancel the ticker if it's still running
- mTicker.removeEntry(old);
+ if (mTickerEnabled) {
+ mTicker.removeEntry(old);
+ }
// Recalculate the position of the sliding windows and the titles.
updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
- if (ENABLE_HEADS_UP && mInterruptingNotificationEntry != null
- && old == mInterruptingNotificationEntry.notification) {
- mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
- }
-
if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0
&& !mNotificationPanel.isTracking() && mState != StatusBarState.KEYGUARD) {
animateCollapsePanels();
@@ -1195,9 +1216,21 @@
final int vis = ent.notification.getNotification().visibility;
if (vis != Notification.VISIBILITY_SECRET) {
// when isLockscreenPublicMode() we show the public form of VISIBILITY_PRIVATE notifications
- ent.row.setShowingPublic(isLockscreenPublicMode()
+ boolean showingPublic = isLockscreenPublicMode()
&& vis == Notification.VISIBILITY_PRIVATE
- && !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId()));
+ && !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId());
+ ent.row.setShowingPublic(showingPublic);
+ if (ent.autoRedacted && ent.legacy) {
+ if (showingPublic) {
+ ent.row.setBackgroundResourceIds(
+ com.android.internal.R.drawable.notification_material_bg,
+ com.android.internal.R.drawable.notification_material_bg_dim);
+ } else {
+ ent.row.setBackgroundResourceIds(
+ com.android.internal.R.drawable.notification_bg,
+ com.android.internal.R.drawable.notification_bg_dim);
+ }
+ }
toShow.add(ent.row);
}
}
@@ -1341,7 +1374,8 @@
mCarrierLabelHeight));
}
- final boolean emergencyCallsShownElsewhere = mEmergencyCallLabel != null;
+ // Emergency calls only is shown in the expanded header now.
+ final boolean emergencyCallsShownElsewhere = true;
final boolean makeVisible =
!(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
&& mStackScroller.getHeight() < (mNotificationPanel.getHeight()
@@ -1564,7 +1598,12 @@
case MSG_SHOW_HEADS_UP:
setHeadsUpVisibility(true);
break;
+ case MSG_DECAY_HEADS_UP:
+ mHeadsUpNotificationView.release();
+ setHeadsUpVisibility(false);
+ break;
case MSG_HIDE_HEADS_UP:
+ mHeadsUpNotificationView.release();
setHeadsUpVisibility(false);
break;
case MSG_ESCALATE_HEADS_UP:
@@ -1577,8 +1616,9 @@
/** if the interrupting notification had a fullscreen intent, fire it now. */
private void escalateHeadsUp() {
- if (mInterruptingNotificationEntry != null) {
- final StatusBarNotification sbn = mInterruptingNotificationEntry.notification;
+ if (mHeadsUpNotificationView.getEntry() != null) {
+ final StatusBarNotification sbn = mHeadsUpNotificationView.getEntry().notification;
+ mHeadsUpNotificationView.release();
final Notification notification = sbn.getNotification();
if (notification.fullScreenIntent != null) {
if (DEBUG)
@@ -1666,7 +1706,6 @@
}
if (mStatusBarWindow != null) {
-
// release focus immediately to kick off focus change transition
mStatusBarWindowManager.setStatusBarFocusable(false);
@@ -1908,6 +1947,10 @@
Integer.toHexString(oldVal), Integer.toHexString(newVal),
Integer.toHexString(diff)));
if (diff != 0) {
+ // we never set the recents bit via this method, so save the prior state to prevent
+ // clobbering the bit below
+ final boolean wasRecentsVisible = (mSystemUiVisibility & View.RECENT_APPS_VISIBLE) > 0;
+
mSystemUiVisibility = newVal;
// update low profile
@@ -1962,6 +2005,11 @@
mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
}
+ // restore the recents bit
+ if (wasRecentsVisible) {
+ mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
+ }
+
// send updated sysui visibility to window manager
notifyUiVisibilityChanged(mSystemUiVisibility);
}
@@ -2118,6 +2166,8 @@
@Override
protected void tick(StatusBarNotification n, boolean firstTime) {
+ if (!mTickerEnabled) return;
+
// no ticking in lights-out mode
if (!areLightsOn()) return;
@@ -2134,7 +2184,7 @@
if (n.getNotification().tickerText != null && mStatusBarWindow != null
&& mStatusBarWindow.getWindowToken() != null) {
if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS
- | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
+ | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) {
mTicker.addEntry(n);
}
}
@@ -2143,10 +2193,14 @@
private class MyTicker extends Ticker {
MyTicker(Context context, View sb) {
super(context, sb);
+ if (!mTickerEnabled) {
+ Log.w(TAG, "MyTicker instantiated with mTickerEnabled=false", new Throwable());
+ }
}
@Override
public void tickerStarting() {
+ if (!mTickerEnabled) return;
mTicking = true;
mStatusBarContents.setVisibility(View.GONE);
mTickerView.setVisibility(View.VISIBLE);
@@ -2156,6 +2210,7 @@
@Override
public void tickerDone() {
+ if (!mTickerEnabled) return;
mStatusBarContents.setVisibility(View.VISIBLE);
mTickerView.setVisibility(View.GONE);
mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null));
@@ -2164,6 +2219,7 @@
}
public void tickerHalting() {
+ if (!mTickerEnabled) return;
if (mStatusBarContents.getVisibility() != View.VISIBLE) {
mStatusBarContents.setVisibility(View.VISIBLE);
mStatusBarContents
@@ -2202,11 +2258,14 @@
pw.println("Current Status Bar state:");
pw.println(" mExpandedVisible=" + mExpandedVisible
+ ", mTrackingPosition=" + mTrackingPosition);
- pw.println(" mTicking=" + mTicking);
+ pw.println(" mTickerEnabled=" + mTickerEnabled);
+ if (mTickerEnabled) {
+ pw.println(" mTicking=" + mTicking);
+ pw.println(" mTickerView: " + viewInfo(mTickerView));
+ }
pw.println(" mTracking=" + mTracking);
pw.println(" mDisplayMetrics=" + mDisplayMetrics);
pw.println(" mStackScroller: " + viewInfo(mStackScroller));
- pw.println(" mTickerView: " + viewInfo(mTickerView));
pw.println(" mStackScroller: " + viewInfo(mStackScroller)
+ " scroll " + mStackScroller.getScrollX()
+ "," + mStackScroller.getScrollY());
@@ -2222,7 +2281,7 @@
pw.print(" mUseHeadsUp=");
pw.println(mUseHeadsUp);
pw.print(" interrupting package: ");
- pw.println(hunStateToString(mInterruptingNotificationEntry));
+ pw.println(hunStateToString(mHeadsUpNotificationView.getEntry()));
dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
if (mNavigationBarView != null) {
pw.print(" mNavigationBarWindowState=");
@@ -2473,6 +2532,7 @@
repositionNavigationBar();
updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
updateShowSearchHoldoff();
+ updateRowStates();
}
@Override
@@ -2496,26 +2556,10 @@
if (!ENABLE_HEADS_UP) return;
if (DEBUG) Log.v(TAG, (vis ? "showing" : "hiding") + " heads up window");
mHeadsUpNotificationView.setVisibility(vis ? View.VISIBLE : View.GONE);
- if (!vis) {
- if (DEBUG) Log.d(TAG, "setting heads up entry to null");
- mInterruptingNotificationEntry = null;
- }
}
public void onHeadsUpDismissed() {
- if (mInterruptingNotificationEntry == null) return;
- mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
- if (mHeadsUpNotificationView.isClearable()) {
- try {
- mBarService.onNotificationClear(
- mInterruptingNotificationEntry.notification.getPackageName(),
- mInterruptingNotificationEntry.notification.getTag(),
- mInterruptingNotificationEntry.notification.getId(),
- mInterruptingNotificationEntry.notification.getUserId());
- } catch (android.os.RemoteException ex) {
- // oh well
- }
- }
+ mHeadsUpNotificationView.dismiss();
}
/**
@@ -2676,7 +2720,9 @@
@Override
protected void haltTicker() {
- mTicker.halt();
+ if (mTickerEnabled) {
+ mTicker.halt();
+ }
}
@Override
@@ -2882,7 +2928,6 @@
mNotificationPanel.setKeyguardShowing(false);
mScrimController.setKeyguardShowing(false);
}
-
updateStackScrollerState();
updatePublicMode();
updateNotifications();
@@ -2898,6 +2943,11 @@
? View.INVISIBLE : View.VISIBLE);
mStackScroller.setScrollingEnabled(!onKeyguard);
mStackScroller.setExpandingEnabled(!onKeyguard);
+ ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
+ mStackScroller.setActivatedChild(null);
+ if (activatedChild != null) {
+ activatedChild.makeInactive(false /* animate */);
+ }
}
public void userActivity() {
@@ -2931,22 +2981,9 @@
private void instantExpandNotificationsPanel() {
- // Make our window larger and the panel visible.
+ // Make our window larger and the panel expanded.
makeExpandedVisible(true);
- mNotificationPanel.setVisibility(View.VISIBLE);
-
- // Wait for window manager to pickup the change, so we know the maximum height of the panel
- // then.
- mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
- new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- if (mStatusBarWindow.getHeight() != getStatusBarHeight()) {
- mNotificationPanel.getViewTreeObserver().removeOnGlobalLayoutListener(this);
- mNotificationPanel.setExpandedFraction(1);
- }
- }
- });
+ mNotificationPanel.instantExpand();
}
private void instantCollapseNotificationPanel() {
@@ -2954,9 +2991,13 @@
}
@Override
- public void onActivated(View view) {
+ public void onActivated(ActivatableNotificationView view) {
userActivity();
mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
+ ActivatableNotificationView previousView = mStackScroller.getActivatedChild();
+ if (previousView != null) {
+ previousView.makeInactive(true /* animate */);
+ }
mStackScroller.setActivatedChild(view);
}
@@ -2969,7 +3010,7 @@
}
@Override
- public void onActivationReset(View view) {
+ public void onActivationReset(ActivatableNotificationView view) {
if (view == mStackScroller.getActivatedChild()) {
mKeyguardIndicationController.hideTransientIndication();
mStackScroller.setActivatedChild(null);
@@ -3100,4 +3141,41 @@
}
}
};
+
+ // Recents
+
+ @Override
+ protected void showRecents(boolean triggeredFromAltTab) {
+ // Set the recents visibility flag
+ mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
+ notifyUiVisibilityChanged(mSystemUiVisibility);
+ super.showRecents(triggeredFromAltTab);
+ }
+
+ @Override
+ protected void hideRecents(boolean triggeredFromAltTab) {
+ // Unset the recents visibility flag
+ mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
+ notifyUiVisibilityChanged(mSystemUiVisibility);
+ super.hideRecents(triggeredFromAltTab);
+ }
+
+ @Override
+ protected void toggleRecents() {
+ // Toggle the recents visibility flag
+ mSystemUiVisibility ^= View.RECENT_APPS_VISIBLE;
+ notifyUiVisibilityChanged(mSystemUiVisibility);
+ super.toggleRecents();
+ }
+
+ @Override
+ public void onVisibilityChanged(boolean visible) {
+ // Update the recents visibility flag
+ if (visible) {
+ mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
+ } else {
+ mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
+ }
+ notifyUiVisibilityChanged(mSystemUiVisibility);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 13d3291..1712124 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -26,6 +26,7 @@
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
+import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel;
@@ -57,6 +58,11 @@
private View mSignalCluster;
private View mSettingsButton;
private View mBrightnessContainer;
+ private View mEmergencyCallsOnly;
+ private TextView mChargingInfo;
+
+ private boolean mShowEmergencyCallsOnly;
+ private boolean mShowChargingInfo;
private int mCollapsedHeight;
private int mExpandedHeight;
@@ -64,6 +70,8 @@
private int mKeyguardWidth = ViewGroup.LayoutParams.MATCH_PARENT;
private int mNormalWidth;
+ private int mPadding;
+ private int mMultiUserExpandedMargin;
private ActivityStarter mActivityStarter;
private BrightnessController mBrightnessController;
@@ -91,6 +99,8 @@
mBrightnessController = new BrightnessController(getContext(),
(ImageView) findViewById(R.id.brightness_icon),
(ToggleSlider) findViewById(R.id.brightness_slider));
+ mEmergencyCallsOnly = findViewById(R.id.header_emergency_calls_only);
+ mChargingInfo = (TextView) findViewById(R.id.header_charging_info);
loadDimens();
updateVisibilities();
addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@@ -112,6 +122,10 @@
mKeyguardHeight = getResources().getDimensionPixelSize(
R.dimen.status_bar_header_height_keyguard);
mNormalWidth = getLayoutParams().width;
+ mPadding = getResources().getDimensionPixelSize(R.dimen.notification_side_padding);
+ mMultiUserExpandedMargin =
+ getResources().getDimensionPixelSize(R.dimen.multi_user_switch_expanded_margin);
+
}
public void setActivityStarter(ActivityStarter activityStarter) {
@@ -138,6 +152,9 @@
updateBrightnessControllerState();
updateZTranslation();
updateClickTargets();
+ updateWidth();
+ updatePadding();
+ updateMultiUserSwitch();
if (mQSPanel != null) {
mQSPanel.setExpanded(expanded && !overscrolled);
}
@@ -173,7 +190,7 @@
}
private void updateWidth() {
- int width = mKeyguardShowing ? mKeyguardWidth : mNormalWidth;
+ int width = (mKeyguardShowing && !mExpanded) ? mKeyguardWidth : mNormalWidth;
ViewGroup.LayoutParams lp = getLayoutParams();
if (width != lp.width) {
lp.width = width;
@@ -195,13 +212,32 @@
if (mSignalCluster != null) {
mSignalCluster.setVisibility(!mExpanded || mOverscrolled ? View.VISIBLE : View.GONE);
}
+ mEmergencyCallsOnly.setVisibility(mExpanded && !mOverscrolled && mShowEmergencyCallsOnly
+ ? VISIBLE : GONE);
+ mChargingInfo.setVisibility(mExpanded && !mOverscrolled && mShowChargingInfo
+ && !mShowEmergencyCallsOnly ? VISIBLE : GONE);
}
private void updateSystemIconsLayoutParams() {
RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsContainer.getLayoutParams();
- lp.addRule(RelativeLayout.START_OF, mExpanded
- ? mSettingsButton.getId()
- : mMultiUserSwitch.getId());
+ boolean systemIconsAboveClock = mExpanded && !mOverscrolled
+ && mShowChargingInfo && !mShowEmergencyCallsOnly;
+ if (systemIconsAboveClock) {
+ lp.addRule(ALIGN_PARENT_START);
+ lp.removeRule(START_OF);
+ } else {
+ lp.addRule(RelativeLayout.START_OF, mExpanded
+ ? mSettingsButton.getId()
+ : mMultiUserSwitch.getId());
+ lp.removeRule(ALIGN_PARENT_START);
+ }
+
+ RelativeLayout.LayoutParams clockLp = (LayoutParams) mDateTime.getLayoutParams();
+ if (systemIconsAboveClock) {
+ clockLp.addRule(BELOW, mChargingInfo.getId());
+ } else {
+ clockLp.addRule(BELOW, mEmergencyCallsOnly.getId());
+ }
}
private void updateBrightnessControllerState() {
@@ -228,6 +264,21 @@
}
}
+ private void updatePadding() {
+ boolean padded = !mKeyguardShowing || mExpanded;
+ int padding = padded ? mPadding : 0;
+ setPaddingRelative(padding, 0, padding, 0);
+ }
+
+ private void updateMultiUserSwitch() {
+ int marginEnd = !mKeyguardShowing || mExpanded ? mMultiUserExpandedMargin : 0;
+ MarginLayoutParams lp = (MarginLayoutParams) mMultiUserSwitch.getLayoutParams();
+ if (marginEnd != lp.getMarginEnd()) {
+ lp.setMarginEnd(marginEnd);
+ mMultiUserSwitch.setLayoutParams(lp);
+ }
+ }
+
public void setExpansion(float height) {
height = (height - mCollapsedHeight) * EXPANSION_RUBBERBAND_FACTOR + mCollapsedHeight;
if (height < mCollapsedHeight) {
@@ -273,6 +324,8 @@
updateWidth();
updateVisibilities();
updateZTranslation();
+ updatePadding();
+ updateMultiUserSwitch();
}
public void setUserInfoController(UserInfoController userInfoController) {
@@ -307,4 +360,29 @@
mBrightnessContainer.animate().alpha(showingDetail ? 0 : 1).withLayer().start();
}
};
+
+ @Override
+ public boolean shouldDelayChildPressedState() {
+ return true;
+ }
+
+ public void setShowEmergencyCallsOnly(boolean show) {
+ mShowEmergencyCallsOnly = show;
+ if (mExpanded) {
+ updateVisibilities();
+ updateSystemIconsLayoutParams();
+ }
+ }
+
+ public void setShowChargingInfo(boolean showChargingInfo) {
+ mShowChargingInfo = showChargingInfo;
+ if (mExpanded) {
+ updateVisibilities();
+ updateSystemIconsLayoutParams();
+ }
+ }
+
+ public void setChargingInfo(CharSequence chargingInfo) {
+ mChargingInfo.setText(chargingInfo);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TickerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TickerView.java
index 8aa3837..bf13751 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TickerView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TickerView.java
@@ -32,7 +32,7 @@
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
- mTicker.reflowText();
+ if (mTicker != null) mTicker.reflowText();
}
public void setTicker(Ticker t) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 6db9bc3..4cf66a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -16,26 +16,49 @@
package com.android.systemui.statusbar.policy;
+import com.android.internal.app.IBatteryStats;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.StatusBarHeaderView;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.text.format.Formatter;
+import android.util.Log;
import java.util.ArrayList;
public class BatteryController extends BroadcastReceiver {
private static final String TAG = "StatusBar.BatteryController";
-
private ArrayList<BatteryStateChangeCallback> mChangeCallbacks =
new ArrayList<BatteryStateChangeCallback>();
+ private Context mContext;
+ private StatusBarHeaderView mStatusBarHeaderView;
+ private IBatteryStats mBatteryInfo;
+
+ private int mLevel;
+ private boolean mPluggedIn;
+ private boolean mCharging;
+ private boolean mCharged;
+
+
public interface BatteryStateChangeCallback {
- public void onBatteryLevelChanged(int level, boolean pluggedIn);
+ public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging);
}
public BatteryController(Context context) {
+ mContext = context;
+
+ mBatteryInfo = IBatteryStats.Stub.asInterface(
+ ServiceManager.getService(BatteryStats.SERVICE_NAME));
+
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
context.registerReceiver(this, filter);
@@ -45,24 +68,59 @@
mChangeCallbacks.add(cb);
}
+ public void setStatusBarHeaderView(StatusBarHeaderView statusBarHeaderView) {
+ mStatusBarHeaderView = statusBarHeaderView;
+ updateStatusBarHeaderView();
+ }
+
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
- final int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
+ mLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
+ mPluggedIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
+
final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
+ mCharged = status == BatteryManager.BATTERY_STATUS_FULL;
+ mCharging = mCharged || status == BatteryManager.BATTERY_STATUS_CHARGING;
- boolean plugged = false;
- switch (status) {
- case BatteryManager.BATTERY_STATUS_CHARGING:
- case BatteryManager.BATTERY_STATUS_FULL:
- plugged = true;
- break;
- }
-
+ updateStatusBarHeaderView();
for (BatteryStateChangeCallback cb : mChangeCallbacks) {
- cb.onBatteryLevelChanged(level, plugged);
+ cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
}
}
}
+
+ private void updateStatusBarHeaderView() {
+ if (mStatusBarHeaderView != null) {
+ mStatusBarHeaderView.setShowChargingInfo(mPluggedIn);
+ mStatusBarHeaderView.setChargingInfo(computeChargingInfo());
+ }
+ }
+
+ private String computeChargingInfo() {
+ if (!mPluggedIn || !mCharged && !mCharging) {
+ return mContext.getResources().getString(R.string.expanded_header_battery_not_charging);
+ }
+
+ if (mCharged) {
+ return mContext.getResources().getString(R.string.expanded_header_battery_charged);
+ }
+
+ // Try fetching charging time from battery stats.
+ try {
+ long chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining();
+ if (chargingTimeRemaining > 0) {
+ String chargingTimeFormatted =
+ Formatter.formatShortElapsedTime(mContext, chargingTimeRemaining);
+ return mContext.getResources().getString(
+ R.string.expanded_header_battery_charging_with_time, chargingTimeFormatted);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling IBatteryStats: ", e);
+ }
+
+ // Fall back to simple charging label.
+ return mContext.getResources().getString(R.string.expanded_header_battery_charging);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index df01c12..0a48e34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -33,9 +33,9 @@
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
-import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.Callback, ExpandHelper.Callback,
ViewTreeObserver.OnComputeInternalInsetsListener {
@@ -51,7 +51,7 @@
private SwipeHelper mSwipeHelper;
private EdgeSwipeHelper mEdgeSwipeHelper;
- private BaseStatusBar mBar;
+ private PhoneStatusBar mBar;
private ExpandHelper mExpandHelper;
private long mStartTouchTime;
@@ -69,7 +69,7 @@
if (DEBUG) Log.v(TAG, "create() " + mTouchSensitivityDelay);
}
- public void setBar(BaseStatusBar bar) {
+ public void setBar(PhoneStatusBar bar) {
mBar = bar;
}
@@ -77,7 +77,12 @@
return mContentHolder;
}
- public boolean setNotification(NotificationData.Entry headsUp) {
+ public boolean showNotification(NotificationData.Entry headsUp) {
+ if (mHeadsUp != null && headsUp != null && !mHeadsUp.key.equals(headsUp.key)) {
+ // bump any previous heads up back to the shade
+ release();
+ }
+
mHeadsUp = headsUp;
if (mContentHolder != null) {
mContentHolder.removeAllViews();
@@ -97,10 +102,57 @@
mSwipeHelper.snapChild(mContentHolder, 1f);
mStartTouchTime = System.currentTimeMillis() + mTouchSensitivityDelay;
+
+ mHeadsUp.setInterruption();
+
+ // 2. Animate mHeadsUpNotificationView in
+ mBar.scheduleHeadsUpOpen();
+
+ // 3. Set alarm to age the notification off
+ mBar.resetHeadsUpDecayTimer();
}
return true;
}
+ public boolean isShowing(String key) {
+ return mHeadsUp != null && mHeadsUp.key.equals(key);
+ }
+
+ /** Discard the Heads Up notification. */
+ public void clear() {
+ mHeadsUp = null;
+ mBar.scheduleHeadsUpClose();
+ }
+
+ /** Respond to dismissal of the Heads Up window. */
+ public void dismiss() {
+ if (mHeadsUp == null) return;
+ if (mHeadsUp.notification.isClearable()) {
+ mBar.onNotificationClear(mHeadsUp.notification);
+ } else {
+ release();
+ }
+ mHeadsUp = null;
+ mBar.scheduleHeadsUpClose();
+ }
+
+ /** Push any current Heads Up notification down into the shade. */
+ public void release() {
+ if (mHeadsUp != null) {
+ mBar.displayNotificationFromHeadsUp(mHeadsUp.notification);
+ }
+ mHeadsUp = null;
+ }
+
+ public void releaseAndClose() {
+ release();
+ mBar.scheduleHeadsUpClose();
+ }
+
+ public NotificationData.Entry getEntry() {
+ return mHeadsUp;
+ }
+
public boolean isClearable() {
return mHeadsUp == null || mHeadsUp.notification.isClearable();
}
@@ -125,7 +177,7 @@
if (mHeadsUp != null) {
// whoops, we're on already!
- setNotification(mHeadsUp);
+ showNotification(mHeadsUp);
}
getViewTreeObserver().addOnComputeInternalInsetsListener(this);
@@ -282,6 +334,10 @@
mTmpTwoArray[1] + mContentHolder.getHeight());
}
+ public void escalate() {
+ mBar.scheduleHeadsUpEscalation();
+ }
+
private class EdgeSwipeHelper implements Gefingerpoken {
private static final boolean DEBUG_EDGE_SWIPE = false;
private final float mTouchSlop;
@@ -335,4 +391,4 @@
return mConsuming;
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index dc8f315..1f68860 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -30,7 +30,7 @@
void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId,
String mobileSignalContentDescriptionId, int dataTypeIconId,
boolean activityIn, boolean activityOut,
- String dataTypeContentDescriptionId, String description);
+ String dataTypeContentDescriptionId, String description, boolean noSim);
void onAirplaneModeChanged(boolean enabled);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 56402a5..4e54e41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -47,6 +47,7 @@
import com.android.internal.util.AsyncChannel;
import com.android.systemui.DemoMode;
import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.StatusBarHeaderView;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -87,6 +88,7 @@
int mQSDataTypeIconId;
int mAirplaneIconId;
boolean mDataActive;
+ boolean mNoSim;
int mLastSignalLevel;
boolean mShowPhoneRSSIForData = false;
boolean mShowAtLeastThreeGees = false;
@@ -143,7 +145,7 @@
ArrayList<TextView> mCombinedLabelViews = new ArrayList<TextView>();
ArrayList<TextView> mMobileLabelViews = new ArrayList<TextView>();
ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>();
- ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>();
+ ArrayList<StatusBarHeaderView> mEmergencyViews = new ArrayList<>();
ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
new ArrayList<NetworkSignalChangedCallback>();
@@ -261,8 +263,8 @@
mWifiLabelViews.add(v);
}
- public void addEmergencyLabelView(TextView v) {
- mEmergencyLabelViews.add(v);
+ public void addEmergencyLabelView(StatusBarHeaderView v) {
+ mEmergencyViews.add(v);
}
public void addSignalCluster(SignalCluster cluster) {
@@ -349,18 +351,18 @@
if (isEmergencyOnly()) {
cb.onMobileDataSignalChanged(false, mQSPhoneSignalIconId,
mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
- mContentDescriptionDataType, null);
+ mContentDescriptionDataType, null, mNoSim);
} else {
if (mIsWimaxEnabled && mWimaxConnected) {
// Wimax is special
cb.onMobileDataSignalChanged(true, mQSPhoneSignalIconId,
mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
- mContentDescriptionDataType, mNetworkName);
+ mContentDescriptionDataType, mNetworkName, mNoSim);
} else {
// Normal mobile data
cb.onMobileDataSignalChanged(mHasMobileDataFeature, mQSPhoneSignalIconId,
mContentDescriptionPhoneSignal, mQSDataTypeIconId, mobileIn, mobileOut,
- mContentDescriptionDataType, mNetworkName);
+ mContentDescriptionDataType, mNetworkName, mNoSim);
}
}
cb.onAirplaneModeChanged(mAirplaneMode);
@@ -736,6 +738,7 @@
// GSM case, we have to check also the sim state
if (mSimState == IccCardConstants.State.READY ||
mSimState == IccCardConstants.State.UNKNOWN) {
+ mNoSim = false;
if (hasService() && mDataState == TelephonyManager.DATA_CONNECTED) {
switch (mDataActivity) {
case TelephonyManager.DATA_ACTIVITY_IN:
@@ -758,6 +761,7 @@
}
} else {
iconId = R.drawable.stat_sys_no_sim;
+ mNoSim = true;
visible = false; // no SIM? no data
}
} else {
@@ -1251,15 +1255,10 @@
}
// e-call label
- N = mEmergencyLabelViews.size();
+ N = mEmergencyViews.size();
for (int i=0; i<N; i++) {
- TextView v = mEmergencyLabelViews.get(i);
- if (!emergencyOnly) {
- v.setVisibility(View.GONE);
- } else {
- v.setText(mobileLabel); // comes from the telephony stack
- v.setVisibility(View.VISIBLE);
- }
+ StatusBarHeaderView v = mEmergencyViews.get(i);
+ v.setShowEmergencyCallsOnly(emergencyOnly);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index b21e12c..6d92b05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.stack;
import android.view.View;
+import com.android.systemui.statusbar.ActivatableNotificationView;
import java.util.ArrayList;
@@ -27,7 +28,7 @@
private ArrayList<View> mDraggedViews = new ArrayList<View>();
private int mScrollY;
private boolean mDimmed;
- private View mActivatedChild;
+ private ActivatableNotificationView mActivatedChild;
private float mOverScrollTopAmount;
private float mOverScrollBottomAmount;
private int mSpeedBumpIndex = -1;
@@ -64,7 +65,7 @@
* In dimmed mode, a child can be activated, which happens on the first tap of the double-tap
* interaction. This child is then scaled normally and its background is fully opaque.
*/
- public void setActivatedChild(View activatedChild) {
+ public void setActivatedChild(ActivatableNotificationView activatedChild) {
mActivatedChild = activatedChild;
}
@@ -72,7 +73,7 @@
return mDimmed;
}
- public View getActivatedChild() {
+ public ActivatableNotificationView getActivatedChild() {
return mActivatedChild;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 20caed8..ccbaed3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -33,6 +33,7 @@
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
+import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.SpeedBumpView;
@@ -240,11 +241,12 @@
mBottomStackPeekSize = context.getResources()
.getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
mStackScrollAlgorithm = new StackScrollAlgorithm(context);
+ mStackScrollAlgorithm.setDimmed(mAmbientState.isDimmed());
mPaddingBetweenElementsDimmed = context.getResources()
.getDimensionPixelSize(R.dimen.notification_padding_dimmed);
mPaddingBetweenElementsNormal = context.getResources()
.getDimensionPixelSize(R.dimen.notification_padding);
- updatePadding(false);
+ updatePadding(mAmbientState.isDimmed());
int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height);
mExpandHelper = new ExpandHelper(getContext(), this,
@@ -760,11 +762,12 @@
}
}
}
-
- mActivePointerId = INVALID_POINTER;
- endDrag();
}
+
+ mActivePointerId = INVALID_POINTER;
+ endDrag();
}
+
break;
case MotionEvent.ACTION_CANCEL:
if (mIsBeingDragged && getChildCount() > 0) {
@@ -966,7 +969,7 @@
* @param animate Should an animation be performed.
*/
public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) {
- setOverScrollAmount(numPixels * getRubberBandFactor(), onTop, animate, true);
+ setOverScrollAmount(numPixels * getRubberBandFactor(onTop), onTop, animate, true);
}
/**
@@ -1002,7 +1005,7 @@
if (animate) {
mStateAnimator.animateOverScrollToAmount(amount, onTop);
} else {
- setOverScrolledPixels(amount / getRubberBandFactor(), onTop);
+ setOverScrolledPixels(amount / getRubberBandFactor(onTop), onTop);
mAmbientState.setOverScrollAmount(amount, onTop);
if (onTop) {
notifyOverscrollTopListener(amount);
@@ -1224,13 +1227,14 @@
mOwnScrollY -= (int) topAmount;
mDontReportNextOverScroll = true;
setOverScrollAmount(0, true, false);
- mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor()
+ mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor(true /* onTop */)
* mOverflingDistance + topAmount;
} else if (velocityY > 0 && bottomAmount > 0) {
mOwnScrollY += bottomAmount;
setOverScrollAmount(0, false, false);
- mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor()
- * mOverflingDistance + bottomAmount;
+ mMaxOverScroll = Math.abs(velocityY) / 1000f
+ * getRubberBandFactor(false /* onTop */) * mOverflingDistance
+ + bottomAmount;
} else {
// it will be set once we reach the boundary
mMaxOverScroll = 0.0f;
@@ -1272,7 +1276,10 @@
return Math.max(desiredPadding, mIntrinsicPadding);
}
- private float getRubberBandFactor() {
+ private float getRubberBandFactor(boolean onTop) {
+ if (!onTop) {
+ return RUBBER_BAND_FACTOR_NORMAL;
+ }
if (mExpandedInThisMotion) {
return RUBBER_BAND_FACTOR_AFTER_EXPAND;
} else if (mIsExpansionChanging) {
@@ -1722,7 +1729,6 @@
mStackScrollAlgorithm.setIsExpanded(isExpanded);
if (!isExpanded) {
mOwnScrollY = 0;
- mSpeedBumpView.collapse();
}
}
@@ -1760,7 +1766,7 @@
/**
* See {@link AmbientState#setActivatedChild}.
*/
- public void setActivatedChild(View activatedChild) {
+ public void setActivatedChild(ActivatableNotificationView activatedChild) {
mAmbientState.setActivatedChild(activatedChild);
if (mAnimationsEnabled) {
mActivateNeedsAnimation = true;
@@ -1769,7 +1775,7 @@
requestChildrenUpdate();
}
- public View getActivatedChild() {
+ public ActivatableNotificationView getActivatedChild() {
return mAmbientState.getActivatedChild();
}
@@ -1791,7 +1797,6 @@
int newVisibility = visible ? VISIBLE : GONE;
mSpeedBumpView.setVisibility(newVisibility);
if (visible) {
- mSpeedBumpView.collapse();
// Make invisible to ensure that the appear animation is played.
mSpeedBumpView.setInvisible();
if (!mIsExpansionChanging) {
@@ -1835,6 +1840,11 @@
return super.dispatchTouchEvent(ev);
}
+ @Override
+ public boolean shouldDelayChildPressedState() {
+ return true;
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index a48cab8..602c22b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -113,7 +113,7 @@
mBottomStackSlowDownLength = context.getResources()
.getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length);
mRoundedRectCornerRadius = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_quantum_rounded_rect_radius);
+ com.android.internal.R.dimen.notification_material_rounded_rect_radius);
}
@@ -186,7 +186,7 @@
if (!child.isTransparent()) {
// Only update the previous values if we are not transparent,
// otherwise we would clip to a transparent view.
- previousNotificationStart = newYTranslation + child.getClipTopAmount();
+ previousNotificationStart = newYTranslation + state.clipTopAmount;
previousNotificationEnd = newNotificationEnd;
previousNotificationIsSwiped = child.getTranslationX() != 0;
}
@@ -228,11 +228,16 @@
View child = algorithmState.visibleChildren.get(i);
StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
childViewState.dimmed = dimmed;
- childViewState.scale = !dimmed || activatedChild == child
+ boolean isActivatedChild = activatedChild == child;
+ childViewState.scale = !dimmed || isActivatedChild
? 1.0f
: DIMMED_SCALE;
- if (dimmed && activatedChild != null && child != activatedChild) {
- childViewState.alpha *= ACTIVATED_INVERSE_ALPHA;
+ if (dimmed && activatedChild != null) {
+ if (!isActivatedChild) {
+ childViewState.alpha *= ACTIVATED_INVERSE_ALPHA;
+ } else {
+ childViewState.zTranslation += 2.0f * mZDistanceBetweenElements;
+ }
}
}
}
@@ -582,6 +587,7 @@
algorithmState.itemsInTopStack += algorithmState.partialInTop;
newSize = Math.max(mCollapsedSize, newSize);
if (i == 0) {
+ algorithmState.itemsInTopStack = 1.0f;
childViewState.height = (int) newSize;
}
algorithmState.lastTopStackIndex = i;
@@ -612,6 +618,20 @@
if (i < algorithmState.itemsInTopStack) {
float stackIndex = algorithmState.itemsInTopStack - i;
stackIndex = Math.min(stackIndex, MAX_ITEMS_IN_TOP_STACK + 2);
+ if (i == 0 && algorithmState.itemsInTopStack < 2.0f) {
+
+ // We only have the top item and an additional item in the top stack,
+ // Interpolate the index from 0 to 2 while the second item is
+ // translating in.
+ stackIndex -= 1.0f;
+ if (algorithmState.scrollY > mCollapsedSize) {
+
+ // Since there is a shadow treshhold, we cant just interpolate from 0 to
+ // 2 but we interpolate from 0.1f to 2.0f when scrolled in. The jump in
+ // height will not be noticable since we have padding in between.
+ stackIndex = 0.1f + stackIndex * 1.9f;
+ }
+ }
childViewState.zTranslation = mZBasicHeight
+ stackIndex * mZDistanceBetweenElements;
} else if (i > (childCount - 1 - algorithmState.itemsInBottomStack)) {
@@ -657,7 +677,7 @@
} else {
// We are expanding the shade, expand it to its full height.
- if (mFirstChildWhileExpanding.getWidth() == 0) {
+ if (!isMaxSizeInitialized(mFirstChildWhileExpanding)) {
// This child was not layouted yet, wait for a layout pass
mFirstChildWhileExpanding
@@ -684,6 +704,14 @@
}
}
+ private boolean isMaxSizeInitialized(ExpandableView child) {
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ return row.isShowingLayoutLayouted();
+ }
+ return child == null || child.getWidth() != 0;
+ }
+
private View findFirstVisibleChild(ViewGroup container) {
int childCount = container.getChildCount();
for (int i = 0; i < childCount; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 94cb16d..1ad4acc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -160,9 +160,8 @@
}
if(child instanceof SpeedBumpView) {
- float speedBumpEnd = newYTranslation + newHeight;
- performSpeedBumpAnimation(i, (SpeedBumpView) child, speedBumpEnd,
- newYTranslation);
+ float lineEnd = newYTranslation + newHeight / 2;
+ performSpeedBumpAnimation(i, (SpeedBumpView) child, lineEnd);
}
}
}
@@ -183,20 +182,12 @@
child.setClipBounds(mClipRect);
}
- private void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, float speedBumpEnd,
- float speedBumpStart) {
+ private void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, float speedBumpEnd) {
View nextChild = getNextChildNotGone(i);
if (nextChild != null) {
ViewState nextState = getViewStateForView(nextChild);
- boolean startIsAboveNext = nextState.yTranslation > speedBumpStart;
+ boolean startIsAboveNext = nextState.yTranslation > speedBumpEnd;
speedBump.animateDivider(startIsAboveNext, null /* onFinishedRunnable */);
-
- // handle expanded case
- if (speedBump.isExpanded()) {
- boolean endIsAboveNext = nextState.yTranslation > speedBumpEnd;
- speedBump.animateExplanationText(endIsAboveNext);
- }
-
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index faea8de..9260aac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -17,14 +17,14 @@
package com.android.systemui.statusbar.tv;
import android.os.IBinder;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.BaseStatusBar;
/*
@@ -51,11 +51,11 @@
}
@Override
- public void addNotificationInternal(StatusBarNotification notification, Ranking ranking) {
+ public void addNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
}
@Override
- protected void updateRankingInternal(Ranking ranking) {
+ protected void updateRankingInternal(RankingMap ranking) {
}
@Override
@@ -63,7 +63,7 @@
}
@Override
- public void removeNotificationInternal(String key, Ranking ranking) {
+ public void removeNotificationInternal(String key, RankingMap ranking) {
}
@Override
@@ -147,6 +147,18 @@
}
@Override
+ public void scheduleHeadsUpOpen() {
+ }
+
+ @Override
+ public void scheduleHeadsUpEscalation() {
+ }
+
+ @Override
+ public void scheduleHeadsUpClose() {
+ }
+
+ @Override
protected int getMaxKeyguardNotifications() {
return 0;
}
@@ -164,10 +176,10 @@
}
@Override
- public void onActivated(View view) {
+ public void onActivated(ActivatableNotificationView view) {
}
@Override
- public void onActivationReset(View view) {
+ public void onActivationReset(ActivatableNotificationView view) {
}
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
index b2ecb61..4ad45a8 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
@@ -40,9 +40,6 @@
private static String TAG = "PhoneFallbackEventHandler";
private static final boolean DEBUG = false;
- // Use the new sessions APIs
- private static final boolean USE_SESSIONS = true;
-
Context mContext;
View mView;
@@ -294,21 +291,7 @@
}
private void handleMediaKeyEvent(KeyEvent keyEvent) {
- if (USE_SESSIONS) {
- MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
- } else {
- IAudioService audioService = IAudioService.Stub.asInterface(
- ServiceManager.checkService(Context.AUDIO_SERVICE));
- if (audioService != null) {
- try {
- audioService.dispatchMediaKeyEvent(keyEvent);
- } catch (RemoteException e) {
- Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
- }
- } else {
- Slog.w(TAG, "Unable to find IAudioService for media key event.");
- }
- }
+ MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
}
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index a8645bc..5e1aa3b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -93,6 +93,7 @@
import android.view.ViewRootImpl;
import android.view.ViewStub;
import android.view.Window;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -118,6 +119,9 @@
private final static String TAG = "PhoneWindow";
private final static boolean SWEEP_OPEN_MENU = false;
+
+ private final static int DEFAULT_BACKGROUND_FADE_DURATION_MS = 300;
+
/**
* Simple callback used by the context menu and its submenus. The options
* menu submenus do not use this (their behavior is more complex).
@@ -246,6 +250,7 @@
private Transition mSharedElementExitTransition;
private Boolean mAllowExitTransitionOverlap;
private Boolean mAllowEnterTransitionOverlap;
+ private long mBackgroundFadeDurationMillis = -1;
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -2627,15 +2632,15 @@
}
@Override
- protected boolean fitSystemWindows(Rect insets) {
- mFrameOffsets.set(insets);
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ mFrameOffsets.set(insets.getSystemWindowInsets());
updateColorViews(insets);
- updateStatusGuard(insets);
+ insets = updateStatusGuard(insets);
updateNavigationGuard(insets);
if (getForeground() != null) {
drawableChanged();
}
- return super.fitSystemWindows(insets);
+ return insets;
}
@Override
@@ -2643,14 +2648,14 @@
return false;
}
- private void updateColorViews(Rect insets) {
+ private void updateColorViews(WindowInsets insets) {
if (mIsFloating || !ActivityManager.isHighEndGfx()) {
// No colors on floating windows or low end devices :(
return;
}
if (insets != null) {
- mLastTopInset = insets.top;
- mLastBottomInset = insets.bottom;
+ mLastTopInset = insets.getSystemWindowInsetTop();
+ mLastBottomInset = insets.getSystemWindowInsetBottom();
}
mStatusColorView = updateColorViewInt(mStatusColorView,
SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
@@ -2689,7 +2694,7 @@
return view;
}
- private void updateStatusGuard(Rect insets) {
+ private WindowInsets updateStatusGuard(WindowInsets insets) {
boolean showStatusGuard = false;
// Show the status guard when the non-overlay contextual action bar is showing
if (mActionModeView != null) {
@@ -2701,9 +2706,9 @@
&& mActionModeView.isShown();
if (nonOverlayShown) {
// set top margin to top insets, show status guard
- if (mlp.topMargin != insets.top) {
+ if (mlp.topMargin != insets.getSystemWindowInsetTop()) {
mlpChanged = true;
- mlp.topMargin = insets.top;
+ mlp.topMargin = insets.getSystemWindowInsetTop();
if (mStatusGuard == null) {
mStatusGuard = new View(mContext);
mStatusGuard.setBackgroundColor(mContext.getResources()
@@ -2719,7 +2724,8 @@
}
}
}
- insets.top = 0; // consume top insets
+ insets = insets.consumeSystemWindowInsets(
+ false, true /* top */, false, false);
showStatusGuard = true;
} else {
// reset top margin
@@ -2736,9 +2742,10 @@
if (mStatusGuard != null) {
mStatusGuard.setVisibility(showStatusGuard ? View.VISIBLE : View.GONE);
}
+ return insets;
}
- private void updateNavigationGuard(Rect insets) {
+ private void updateNavigationGuard(WindowInsets insets) {
// IMEs lay out below the nav bar, but the content view must not (for back compat)
if (getAttributes().type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
// prevent the content view from including the nav bar height
@@ -2746,7 +2753,7 @@
if (mContentParent.getLayoutParams() instanceof MarginLayoutParams) {
MarginLayoutParams mlp =
(MarginLayoutParams) mContentParent.getLayoutParams();
- mlp.bottomMargin = insets.bottom;
+ mlp.bottomMargin = insets.getSystemWindowInsetBottom();
mContentParent.setLayoutParams(mlp);
}
}
@@ -2756,11 +2763,11 @@
mNavigationGuard.setBackgroundColor(mContext.getResources()
.getColor(R.color.input_method_navigation_guard));
addView(mNavigationGuard, indexOfChild(mNavigationColorView), new LayoutParams(
- LayoutParams.MATCH_PARENT, insets.bottom,
+ LayoutParams.MATCH_PARENT, insets.getSystemWindowInsetBottom(),
Gravity.START | Gravity.BOTTOM));
} else {
LayoutParams lp = (LayoutParams) mNavigationGuard.getLayoutParams();
- lp.height = insets.bottom;
+ lp.height = insets.getSystemWindowInsetBottom();
mNavigationGuard.setLayoutParams(lp);
}
}
@@ -3419,6 +3426,12 @@
com.android.internal.R.styleable.
Window_windowAllowExitTransitionOverlap, true);
}
+ if (mBackgroundFadeDurationMillis < 0) {
+ mBackgroundFadeDurationMillis = getWindowStyle().getInteger(
+ com.android.internal.R.styleable.
+ Window_windowTransitionBackgroundFadeDuration,
+ DEFAULT_BACKGROUND_FADE_DURATION_MS);
+ }
}
}
}
@@ -3825,6 +3838,20 @@
return (mAllowExitTransitionOverlap == null) ? true : mAllowExitTransitionOverlap;
}
+ @Override
+ public long getTransitionBackgroundFadeDuration() {
+ return (mBackgroundFadeDurationMillis < 0) ? DEFAULT_BACKGROUND_FADE_DURATION_MS
+ : mBackgroundFadeDurationMillis;
+ }
+
+ @Override
+ public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) {
+ if (fadeDurationMillis < 0) {
+ throw new IllegalArgumentException("negative durations are not allowed");
+ }
+ mBackgroundFadeDurationMillis = fadeDurationMillis;
+ }
+
private static final class DrawableFeatureState {
DrawableFeatureState(int _featureId) {
featureId = _featureId;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 03d29c0..bc2671011 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -144,9 +144,6 @@
static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true;
static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
- // Whether to use the new Session APIs
- static final boolean USE_SESSIONS = true;
-
static final int SHORT_PRESS_POWER_NOTHING = 0;
static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1;
static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2;
@@ -296,6 +293,7 @@
WindowState mLastInputMethodWindow = null;
WindowState mLastInputMethodTargetWindow = null;
+ boolean mRecentsVisible;
int mRecentAppsHeldModifiers;
boolean mLanguageSwitchKeyPressed;
@@ -305,6 +303,7 @@
boolean mSystemReady;
boolean mSystemBooted;
boolean mHdmiPlugged;
+ IUiModeManager mUiModeManager;
int mUiMode;
int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
int mLidOpenRotation;
@@ -434,6 +433,12 @@
* be done once per window. */
private WindowState mWinDismissingKeyguard;
+ /** The window that is currently showing "over" the keyguard. If there is an app window
+ * belonging to another app on top of this the keyguard shows. If there is a fullscreen
+ * app window under this, still dismiss the keyguard but don't show the app underneath. Show
+ * the wallpaper. */
+ private WindowState mWinShowWhenLocked;
+
boolean mShowingLockscreen;
boolean mShowingDream;
boolean mDreamingLockscreen;
@@ -1668,8 +1673,9 @@
}
@Override
- public boolean doesForceHide(WindowManager.LayoutParams attrs) {
- return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+ public boolean isForceHiding(WindowManager.LayoutParams attrs) {
+ return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
+ (isKeyguardHostWindow(attrs) && isKeyguardSecureIncludingHidden());
}
@Override
@@ -2632,6 +2638,11 @@
}
}
});
+ } else if (mRecentsVisible) {
+ // Recents is started on top of Home, so when we launch home while recents is open, let
+ // it do its own animation and then finish itself
+ sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
+ hideRecentApps(false);
} else {
// no keyguard stuff to worry about, just launch home!
try {
@@ -2723,6 +2734,7 @@
public int adjustSystemUiVisibilityLw(int visibility) {
mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
+ mRecentsVisible = (visibility & View.RECENT_APPS_VISIBLE) > 0;
// Reset any bits in mForceClearingStatusBarVisibility that
// are now clear.
@@ -3112,10 +3124,11 @@
/** {@inheritDoc} */
@Override
- public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs,
- WindowState attached) {
+ public void layoutWindowLw(WindowState win, WindowState attached) {
// we've already done the status bar
- if ((win == mStatusBar && !doesForceHide(attrs)) || win == mNavigationBar) {
+ final WindowManager.LayoutParams attrs = win.getAttrs();
+ if ((win == mStatusBar && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) == 0) ||
+ win == mNavigationBar) {
return;
}
final boolean isDefaultDisplay = win.isDefaultDisplay();
@@ -3596,12 +3609,12 @@
mDismissKeyguard = DISMISS_KEYGUARD_NONE;
mShowingLockscreen = false;
mShowingDream = false;
+ mWinShowWhenLocked = null;
}
/** {@inheritDoc} */
@Override
- public void applyPostLayoutPolicyLw(WindowState win,
- WindowManager.LayoutParams attrs) {
+ public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs) {
if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
+ win.isVisibleOrBehindKeyguardLw());
final int fl = PolicyControl.getWindowFlags(win, attrs);
@@ -3639,9 +3652,17 @@
final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0;
final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0;
+ final boolean secureKeyguard = isKeyguardSecure();
if (appWindow) {
- if (showWhenLocked || (dismissKeyguard && !isKeyguardSecure())) {
+ if (showWhenLocked || (dismissKeyguard && !secureKeyguard)) {
+ // Remove any previous windows with the same appToken.
mAppsToBeHidden.remove(win.getAppToken());
+ if (mAppsToBeHidden.isEmpty() && showWhenLocked &&
+ isKeyguardSecureIncludingHidden()) {
+ mWinShowWhenLocked = win;
+ mHideLockScreen = true;
+ mForceStatusBarFromKeyguard = false;
+ }
} else {
mAppsToBeHidden.add(win.getAppToken());
}
@@ -3663,13 +3684,18 @@
mDismissKeyguard = mWinDismissingKeyguard == win ?
DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
mWinDismissingKeyguard = win;
- mForceStatusBarFromKeyguard = mShowingLockscreen && isKeyguardSecure();
+ mForceStatusBarFromKeyguard = mShowingLockscreen && secureKeyguard;
}
}
if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
mAllowLockscreenWhenOn = true;
}
}
+
+ if (mWinShowWhenLocked != null &&
+ mWinShowWhenLocked.getAppToken() != win.getAppToken()) {
+ win.hideLw(false);
+ }
}
}
}
@@ -3677,6 +3703,16 @@
/** {@inheritDoc} */
@Override
public int finishPostLayoutPolicyLw() {
+ if (mWinShowWhenLocked != null &&
+ mWinShowWhenLocked != mTopFullscreenOpaqueWindowState) {
+ // A dialog is dismissing the keyguard. Put the wallpaper behind it and hide the
+ // fullscreen window.
+ // TODO: Make sure FLAG_SHOW_WALLPAPER is restored when dialog is dismissed. Or not.
+ mWinShowWhenLocked.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+ mTopFullscreenOpaqueWindowState.hideLw(false);
+ mTopFullscreenOpaqueWindowState = mWinShowWhenLocked;
+ }
+
int changes = 0;
boolean topIsFullscreen = false;
@@ -3935,6 +3971,7 @@
* controlled by this device, or through remote submix).
*/
boolean isMusicActive() {
+
final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
if (am == null) {
Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
@@ -3943,43 +3980,6 @@
return am.isLocalOrRemoteMusicActive();
}
- /**
- * Tell the audio service to adjust the volume appropriate to the event.
- * @param keycode
- */
- void handleVolumeKey(int stream, int keycode) {
- IAudioService audioService = getAudioService();
- if (audioService == null) {
- return;
- }
- try {
- // when audio is playing locally, we shouldn't have to hold a wake lock
- // during the call, but we do it as a precaution for the rare possibility
- // that the music stops right before we call this.
- // Otherwise we might also be in a remote playback case.
- // TODO: Actually handle MUTE.
- mBroadcastWakeLock.acquire();
- if (stream == AudioSystem.STREAM_MUSIC) {
- audioService.adjustLocalOrRemoteStreamVolume(stream,
- keycode == KeyEvent.KEYCODE_VOLUME_UP
- ? AudioManager.ADJUST_RAISE
- : AudioManager.ADJUST_LOWER,
- mContext.getOpPackageName());
- } else {
- audioService.adjustStreamVolume(stream,
- keycode == KeyEvent.KEYCODE_VOLUME_UP
- ? AudioManager.ADJUST_RAISE
- : AudioManager.ADJUST_LOWER,
- 0,
- mContext.getOpPackageName());
- }
- } catch (RemoteException e) {
- Log.w(TAG, "IAudioService.adjust*StreamVolume() threw RemoteException " + e);
- } finally {
- mBroadcastWakeLock.release();
- }
- }
-
final Object mScreenshotLock = new Object();
ServiceConnection mScreenshotConnection = null;
@@ -4079,11 +4079,6 @@
+ " policyFlags=" + Integer.toHexString(policyFlags));
}
- if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
- && event.getRepeatCount() == 0) {
- performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
- }
-
// Basic policy based on interactive state.
int result;
boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
@@ -4106,6 +4101,10 @@
return result;
}
+ boolean useHapticFeedback = down
+ && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
+ && event.getRepeatCount() == 0;
+
// Handle special keys.
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -4163,16 +4162,20 @@
if (telephonyManager.isOffhook()
&& (result & ACTION_PASS_TO_USER) == 0) {
// If we are in call but we decided not to pass the key to
- // the application, handle the volume change here.
- handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
+ // the application, just pass it to the session service.
+
+ MediaSessionLegacyHelper.getHelper(mContext)
+ .sendMediaButtonEvent(event, true);
break;
}
}
- if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) {
- // If music is playing but we decided not to pass the key to the
- // application, handle the volume change here.
- handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
+ if ((result & ACTION_PASS_TO_USER) == 0) {
+ // If we aren't passing to the user and no one else
+ // handled it send it to the session manager to figure
+ // out.
+ MediaSessionLegacyHelper.getHelper(mContext)
+ .sendMediaButtonEvent(event, true);
break;
}
}
@@ -4252,6 +4255,9 @@
case KeyEvent.KEYCODE_SLEEP: {
result &= ~ACTION_PASS_TO_USER;
+ if (!mPowerManager.isInteractive()) {
+ useHapticFeedback = false; // suppress feedback if already non-interactive
+ }
mPowerManager.goToSleep(event.getEventTime());
isWakeKey = false;
break;
@@ -4318,6 +4324,10 @@
}
}
+ if (useHapticFeedback) {
+ performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+ }
+
if (isWakeKey) {
mPowerManager.wakeUp(event.getEventTime());
}
@@ -4414,18 +4424,7 @@
void dispatchMediaKeyWithWakeLockToAudioService(KeyEvent event) {
if (ActivityManagerNative.isSystemReady()) {
- if (USE_SESSIONS) {
- MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(event, true);
- } else {
- IAudioService audioService = getAudioService();
- if (audioService != null) {
- try {
- audioService.dispatchMediaKeyEventUnderWakelock(event);
- } catch (RemoteException e) {
- Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e);
- }
- }
- }
+ MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(event, true);
}
}
@@ -4632,6 +4631,11 @@
return mKeyguardDelegate.isSecure();
}
+ // Returns true if keyguard is currently locked whether or not it is currently hidden.
+ private boolean isKeyguardSecureIncludingHidden() {
+ return mKeyguardDelegate.isSecure() && mKeyguardDelegate.isShowing();
+ }
+
/** {@inheritDoc} */
public boolean inKeyguardRestrictedKeyInputMode() {
if (mKeyguardDelegate == null) return false;
@@ -4941,6 +4945,7 @@
mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
mKeyguardDelegate.onSystemReady();
+ updateUiMode();
synchronized (mLock) {
updateOrientationListenerLp();
mSystemReady = true;
@@ -5129,6 +5134,17 @@
}
}
+ void updateUiMode() {
+ if (mUiModeManager == null) {
+ mUiModeManager = IUiModeManager.Stub.asInterface(
+ ServiceManager.getService(Context.UI_MODE_SERVICE));
+ }
+ try {
+ mUiMode = mUiModeManager.getCurrentModeType();
+ } catch (RemoteException e) {
+ }
+ }
+
void updateRotation(boolean alwaysSendConfiguration) {
try {
//set orientation on WindowManager
@@ -5174,6 +5190,12 @@
if (ENABLE_DESK_DOCK_HOME_CAPTURE) {
intent = mDeskDockIntent;
}
+ } else if (mUiMode == Configuration.UI_MODE_TYPE_WATCH
+ && (mDockMode == Intent.EXTRA_DOCK_STATE_DESK
+ || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK
+ || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK)) {
+ // Always launch dock home from home when watch is docked, if it exists.
+ intent = mDeskDockIntent;
}
if (intent == null) {
diff --git a/rs/java/android/renderscript/FieldPacker.java b/rs/java/android/renderscript/FieldPacker.java
index 0e57232..c9bba69 100644
--- a/rs/java/android/renderscript/FieldPacker.java
+++ b/rs/java/android/renderscript/FieldPacker.java
@@ -233,6 +233,9 @@
if (obj != null) {
if (RenderScript.sPointerSize == 8) {
addI64(obj.getID(null));
+ addI64(0);
+ addI64(0);
+ addI64(0);
}
else {
addI32((int)obj.getID(null));
@@ -240,6 +243,9 @@
} else {
if (RenderScript.sPointerSize == 8) {
addI64(0);
+ addI64(0);
+ addI64(0);
+ addI64(0);
} else {
addI32(0);
}
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 8cac22d..44de480 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -64,23 +64,23 @@
static Method registerNativeFree;
/*
- * Context creation flag which specifies a normal context.
+ * Context creation flag that specifies a normal context.
*/
- public static final long CREATE_FLAG_NONE = 0x0000;
+ public static final int CREATE_FLAG_NONE = 0x0000;
/*
* Context creation flag which specifies a context optimized for low
* latency over peak performance. This is a hint and may have no effect
* on some implementations.
*/
- public static final long CREATE_FLAG_LOW_LATENCY = 0x0002;
+ public static final int CREATE_FLAG_LOW_LATENCY = 0x0002;
/*
* Context creation flag which specifies a context optimized for long
* battery life over peak performance. This is a hint and may have no effect
* on some implementations.
*/
- public static final long CREATE_FLAG_LOW_POWER = 0x0004;
+ public static final int CREATE_FLAG_LOW_POWER = 0x0004;
/*
* Detect the bitness of the VM to allow FieldPacker to do the right thing.
@@ -1181,7 +1181,7 @@
* @param ctx The context.
* @return RenderScript
*/
- public static RenderScript create(Context ctx, int sdkVersion, ContextType ct, long flags) {
+ public static RenderScript create(Context ctx, int sdkVersion, ContextType ct, int flags) {
if (!sInitialized) {
Log.e(LOG_TAG, "RenderScript.create() called when disabled; someone is likely to crash");
return null;
@@ -1194,7 +1194,7 @@
RenderScript rs = new RenderScript(ctx);
rs.mDev = rs.nDeviceCreate();
- rs.mContext = rs.nContextCreate(rs.mDev, (int)flags, sdkVersion, ct.mID);
+ rs.mContext = rs.nContextCreate(rs.mDev, flags, sdkVersion, ct.mID);
rs.mContextType = ct;
if (rs.mContext == 0) {
throw new RSDriverException("Failed to create RS context.");
@@ -1236,7 +1236,7 @@
* @param flags The OR of the CREATE_FLAG_* options desired
* @return RenderScript
*/
- public static RenderScript create(Context ctx, ContextType ct, long flags) {
+ public static RenderScript create(Context ctx, ContextType ct, int flags) {
int v = ctx.getApplicationInfo().targetSdkVersion;
return create(ctx, v, ct, flags);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index eca1bc1..1be1572 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1640,6 +1640,17 @@
pw.println("}]");
pw.println();
}
+ final int windowCount = mSecurityPolicy.mWindows.size();
+ for (int j = 0; j < windowCount; j++) {
+ if (j > 0) {
+ pw.append(',');
+ pw.println();
+ }
+ pw.append("Window[");
+ AccessibilityWindowInfo window = mSecurityPolicy.mWindows.get(j);
+ pw.append(window.toString());
+ pw.append(']');
+ }
}
}
@@ -3283,7 +3294,7 @@
}
if (mTouchInteractionInProgress && activeWindowGone) {
- mActiveWindowId = INVALID_WINDOW_ID;
+ mActiveWindowId = mFocusedWindowId;
}
// Focused window may change the active one, so set the
@@ -3291,7 +3302,7 @@
for (int i = 0; i < windowCount; i++) {
AccessibilityWindowInfo window = mWindows.get(i);
if (window.getId() == mActiveWindowId) {
- window.setActive(true);
+ window.setActive(true);
}
}
}
@@ -3336,10 +3347,11 @@
// The active window also determined events from which
// windows are delivered.
synchronized (mLock) {
- mFocusedWindowId = getFocusedWindowId();
- if (mWindowsForAccessibilityCallback == null
- && windowId == mFocusedWindowId) {
- mActiveWindowId = windowId;
+ if (mWindowsForAccessibilityCallback == null) {
+ mFocusedWindowId = getFocusedWindowId();
+ if (windowId == mFocusedWindowId) {
+ mActiveWindowId = windowId;
+ }
}
}
} break;
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 14c15a7..3b1e88a 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -28,6 +28,7 @@
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupTransport;
import android.app.backup.FullBackup;
+import android.app.backup.RestoreDescription;
import android.app.backup.RestoreSet;
import android.app.backup.IBackupManager;
import android.app.backup.IFullBackupRestoreObserver;
@@ -201,7 +202,7 @@
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_FULL_BACKUP = 2;
+ private static final int MSG_RUN_ADB_BACKUP = 2;
private static final int MSG_RUN_RESTORE = 3;
private static final int MSG_RUN_CLEAR = 4;
private static final int MSG_RUN_INITIALIZE = 5;
@@ -209,10 +210,11 @@
private static final int MSG_TIMEOUT = 7;
private static final int MSG_RESTORE_TIMEOUT = 8;
private static final int MSG_FULL_CONFIRMATION_TIMEOUT = 9;
- private static final int MSG_RUN_FULL_RESTORE = 10;
+ private static final int MSG_RUN_ADB_RESTORE = 10;
private static final int MSG_RETRY_INIT = 11;
private static final int MSG_RETRY_CLEAR = 12;
private static final int MSG_WIDGET_BROADCAST = 13;
+ private static final int MSG_RUN_FULL_TRANSPORT_BACKUP = 14;
// backup task state machine tick
static final int MSG_BACKUP_RESTORE_STEP = 20;
@@ -448,11 +450,12 @@
public boolean doWidgets;
public boolean allApps;
public boolean includeSystem;
+ public boolean doCompress;
public String[] packages;
FullBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveObbs,
boolean saveShared, boolean alsoWidgets, boolean doAllApps, boolean doSystem,
- String[] pkgList) {
+ boolean compress, String[] pkgList) {
fd = output;
includeApks = saveApks;
includeObbs = saveObbs;
@@ -460,6 +463,7 @@
doWidgets = alsoWidgets;
allApps = doAllApps;
includeSystem = doSystem;
+ doCompress = compress;
packages = pkgList;
}
}
@@ -646,17 +650,25 @@
break;
}
- case MSG_RUN_FULL_BACKUP:
+ case MSG_RUN_ADB_BACKUP:
{
// TODO: refactor full backup to be a looper-based state machine
// similar to normal backup/restore.
FullBackupParams params = (FullBackupParams)msg.obj;
- PerformFullBackupTask task = new PerformFullBackupTask(params.fd,
+ PerformAdbBackupTask task = new PerformAdbBackupTask(params.fd,
params.observer, params.includeApks, params.includeObbs,
params.includeShared, params.doWidgets,
params.curPassword, params.encryptPassword,
- params.allApps, params.includeSystem, params.packages, params.latch);
- (new Thread(task)).start();
+ params.allApps, params.includeSystem, params.doCompress,
+ params.packages, params.latch);
+ (new Thread(task, "adb-backup")).start();
+ break;
+ }
+
+ case MSG_RUN_FULL_TRANSPORT_BACKUP:
+ {
+ PerformFullTransportBackupTask task = (PerformFullTransportBackupTask) msg.obj;
+ (new Thread(task, "transport-backup")).start();
break;
}
@@ -673,7 +685,7 @@
break;
}
- case MSG_RUN_FULL_RESTORE:
+ case MSG_RUN_ADB_RESTORE:
{
// TODO: refactor full restore to be a looper-based state machine
// similar to normal backup/restore.
@@ -681,7 +693,7 @@
PerformFullRestoreTask task = new PerformFullRestoreTask(params.fd,
params.curPassword, params.encryptPassword,
params.observer, params.latch);
- (new Thread(task)).start();
+ (new Thread(task, "adb-restore")).start();
break;
}
@@ -2618,13 +2630,6 @@
// ----- Full backup/restore to a file/socket -----
- abstract class ObbServiceClient {
- public IObbBackupService mObbService;
- public void setObbBinder(IObbBackupService binder) {
- mObbService = binder;
- }
- }
-
class FullBackupObbConnection implements ServiceConnection {
volatile IObbBackupService mService;
@@ -2736,24 +2741,15 @@
}
}
- class PerformFullBackupTask extends ObbServiceClient implements Runnable {
- ParcelFileDescriptor mOutputFile;
- DeflaterOutputStream mDeflater;
+ // Core logic for performing one package's full backup, gathering the tarball from the
+ // application and emitting it to the designated OutputStream.
+ class FullBackupEngine {
+ OutputStream mOutput;
IFullBackupRestoreObserver mObserver;
- boolean mIncludeApks;
- boolean mIncludeObbs;
- boolean mIncludeShared;
- boolean mDoWidgets;
- boolean mAllApps;
- final boolean mIncludeSystem;
- ArrayList<String> mPackages;
- String mCurrentPassword;
- String mEncryptPassword;
- AtomicBoolean mLatchObject;
File mFilesDir;
File mManifestFile;
File mMetadataFile;
-
+ boolean mIncludeApks;
class FullBackupRunner implements Runnable {
PackageInfo mPackage;
@@ -2823,326 +2819,17 @@
}
}
- PerformFullBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer,
- boolean includeApks, boolean includeObbs, boolean includeShared,
- boolean doWidgets, String curPassword, String encryptPassword, boolean doAllApps,
- boolean doSystem, String[] packages, AtomicBoolean latch) {
- mOutputFile = fd;
- mObserver = observer;
- mIncludeApks = includeApks;
- mIncludeObbs = includeObbs;
- mIncludeShared = includeShared;
- mDoWidgets = doWidgets;
- mAllApps = doAllApps;
- mIncludeSystem = doSystem;
- mPackages = (packages == null)
- ? new ArrayList<String>()
- : new ArrayList<String>(Arrays.asList(packages));
- mCurrentPassword = curPassword;
- // when backing up, if there is a current backup password, we require that
- // the user use a nonempty encryption password as well. if one is supplied
- // in the UI we use that, but if the UI was left empty we fall back to the
- // current backup password (which was supplied by the user as well).
- if (encryptPassword == null || "".equals(encryptPassword)) {
- mEncryptPassword = curPassword;
- } else {
- mEncryptPassword = encryptPassword;
- }
- mLatchObject = latch;
-
+ FullBackupEngine(OutputStream output, String packageName, boolean alsoApks) {
+ mOutput = output;
+ mIncludeApks = alsoApks;
mFilesDir = new File("/data/system");
mManifestFile = new File(mFilesDir, BACKUP_MANIFEST_FILENAME);
mMetadataFile = new File(mFilesDir, BACKUP_METADATA_FILENAME);
}
- void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) {
- for (String pkgName : pkgNames) {
- if (!set.containsKey(pkgName)) {
- try {
- PackageInfo info = mPackageManager.getPackageInfo(pkgName,
- PackageManager.GET_SIGNATURES);
- set.put(pkgName, info);
- } catch (NameNotFoundException e) {
- Slog.w(TAG, "Unknown package " + pkgName + ", skipping");
- }
- }
- }
- }
- @Override
- public void run() {
- Slog.i(TAG, "--- Performing full-dataset backup ---");
-
- TreeMap<String, PackageInfo> packagesToBackup = new TreeMap<String, PackageInfo>();
- FullBackupObbConnection obbConnection = new FullBackupObbConnection();
- obbConnection.establish(); // we'll want this later
-
- sendStartBackup();
-
- // doAllApps supersedes the package set if any
- if (mAllApps) {
- List<PackageInfo> allPackages = mPackageManager.getInstalledPackages(
- PackageManager.GET_SIGNATURES);
- for (int i = 0; i < allPackages.size(); i++) {
- PackageInfo pkg = allPackages.get(i);
- // Exclude system apps if we've been asked to do so
- if (mIncludeSystem == true
- || ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
- packagesToBackup.put(pkg.packageName, pkg);
- }
- }
- }
-
- // If we're doing widget state as well, ensure that we have all the involved
- // host & provider packages in the set
- if (mDoWidgets) {
- List<String> pkgs =
- AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_OWNER);
- if (pkgs != null) {
- if (MORE_DEBUG) {
- Slog.i(TAG, "Adding widget participants to backup set:");
- StringBuilder sb = new StringBuilder(128);
- sb.append(" ");
- for (String s : pkgs) {
- sb.append(' ');
- sb.append(s);
- }
- Slog.i(TAG, sb.toString());
- }
- addPackagesToSet(packagesToBackup, pkgs);
- }
- }
-
- // Now process the command line argument packages, if any. Note that explicitly-
- // named system-partition packages will be included even if includeSystem was
- // set to false.
- if (mPackages != null) {
- addPackagesToSet(packagesToBackup, mPackages);
- }
-
- // Now we cull any inapplicable / inappropriate packages from the set
- Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator();
- while (iter.hasNext()) {
- PackageInfo pkg = iter.next().getValue();
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0
- || pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
- // Cull any packages that have indicated that backups are not permitted, as well
- // as any explicit mention of the 'special' shared-storage agent package (we
- // handle that one at the end).
- iter.remove();
- } else if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
- && (pkg.applicationInfo.backupAgentName == null)) {
- // Cull any packages that run as system-domain uids but do not define their
- // own backup agents
- if (MORE_DEBUG) {
- Slog.i(TAG, "... ignoring non-agent system package " + pkg.packageName);
- }
- iter.remove();
- }
- }
-
- // flatten the set of packages now so we can explicitly control the ordering
- ArrayList<PackageInfo> backupQueue =
- new ArrayList<PackageInfo>(packagesToBackup.values());
-
- FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor());
- OutputStream out = null;
-
- PackageInfo pkg = null;
- try {
- boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
- boolean compressing = COMPRESS_FULL_BACKUPS;
- OutputStream finalOutput = ofstream;
-
- // Verify that the given password matches the currently-active
- // backup password, if any
- if (!backupPasswordMatches(mCurrentPassword)) {
- if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
- return;
- }
-
- // Write the global file header. All strings are UTF-8 encoded; lines end
- // with a '\n' byte. Actual backup data begins immediately following the
- // final '\n'.
- //
- // line 1: "ANDROID BACKUP"
- // line 2: backup file format version, currently "2"
- // line 3: compressed? "0" if not compressed, "1" if compressed.
- // line 4: name of encryption algorithm [currently only "none" or "AES-256"]
- //
- // When line 4 is not "none", then additional header data follows:
- //
- // line 5: user password salt [hex]
- // line 6: master key checksum salt [hex]
- // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
- // line 8: IV of the user key [hex]
- // line 9: master key blob [hex]
- // IV of the master key, master key itself, master key checksum hash
- //
- // The master key checksum is the master key plus its checksum salt, run through
- // 10k rounds of PBKDF2. This is used to verify that the user has supplied the
- // correct password for decrypting the archive: the master key decrypted from
- // the archive using the user-supplied password is also run through PBKDF2 in
- // this way, and if the result does not match the checksum as stored in the
- // archive, then we know that the user-supplied password does not match the
- // archive's.
- StringBuilder headerbuf = new StringBuilder(1024);
-
- headerbuf.append(BACKUP_FILE_HEADER_MAGIC);
- headerbuf.append(BACKUP_FILE_VERSION); // integer, no trailing \n
- headerbuf.append(compressing ? "\n1\n" : "\n0\n");
-
- try {
- // Set up the encryption stage if appropriate, and emit the correct header
- if (encrypting) {
- finalOutput = emitAesBackupHeader(headerbuf, finalOutput);
- } else {
- headerbuf.append("none\n");
- }
-
- byte[] header = headerbuf.toString().getBytes("UTF-8");
- ofstream.write(header);
-
- // Set up the compression stage feeding into the encryption stage (if any)
- if (compressing) {
- Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
- finalOutput = new DeflaterOutputStream(finalOutput, deflater, true);
- }
-
- out = finalOutput;
- } catch (Exception e) {
- // Should never happen!
- Slog.e(TAG, "Unable to emit archive header", e);
- return;
- }
-
- // Shared storage if requested
- if (mIncludeShared) {
- try {
- pkg = mPackageManager.getPackageInfo(SHARED_BACKUP_AGENT_PACKAGE, 0);
- backupQueue.add(pkg);
- } catch (NameNotFoundException e) {
- Slog.e(TAG, "Unable to find shared-storage backup handler");
- }
- }
-
- // Now back up the app data via the agent mechanism
- int N = backupQueue.size();
- for (int i = 0; i < N; i++) {
- pkg = backupQueue.get(i);
- backupOnePackage(pkg, out);
-
- // after the app's agent runs to handle its private filesystem
- // contents, back up any OBB content it has on its behalf.
- if (mIncludeObbs) {
- boolean obbOkay = obbConnection.backupObbs(pkg, out);
- if (!obbOkay) {
- throw new RuntimeException("Failure writing OBB stack for " + pkg);
- }
- }
- }
-
- // Done!
- finalizeBackup(out);
- } catch (RemoteException e) {
- Slog.e(TAG, "App died during full backup");
- } catch (Exception e) {
- Slog.e(TAG, "Internal exception during full backup", e);
- } finally {
- tearDown(pkg);
- try {
- if (out != null) out.close();
- mOutputFile.close();
- } catch (IOException e) {
- /* nothing we can do about this */
- }
- synchronized (mCurrentOpLock) {
- mCurrentOperations.clear();
- }
- synchronized (mLatchObject) {
- mLatchObject.set(true);
- mLatchObject.notifyAll();
- }
- sendEndBackup();
- obbConnection.tearDown();
- if (DEBUG) Slog.d(TAG, "Full backup pass complete.");
- mWakelock.release();
- }
- }
-
- private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
- OutputStream ofstream) throws Exception {
- // User key will be used to encrypt the master key.
- byte[] newUserSalt = randomBytes(PBKDF2_SALT_SIZE);
- SecretKey userKey = buildPasswordKey(PBKDF_CURRENT, mEncryptPassword, newUserSalt,
- PBKDF2_HASH_ROUNDS);
-
- // the master key is random for each backup
- byte[] masterPw = new byte[256 / 8];
- mRng.nextBytes(masterPw);
- byte[] checksumSalt = randomBytes(PBKDF2_SALT_SIZE);
-
- // primary encryption of the datastream with the random key
- Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
- SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES");
- c.init(Cipher.ENCRYPT_MODE, masterKeySpec);
- OutputStream finalOutput = new CipherOutputStream(ofstream, c);
-
- // line 4: name of encryption algorithm
- headerbuf.append(ENCRYPTION_ALGORITHM_NAME);
- headerbuf.append('\n');
- // line 5: user password salt [hex]
- headerbuf.append(byteArrayToHex(newUserSalt));
- headerbuf.append('\n');
- // line 6: master key checksum salt [hex]
- headerbuf.append(byteArrayToHex(checksumSalt));
- headerbuf.append('\n');
- // line 7: number of PBKDF2 rounds used [decimal]
- headerbuf.append(PBKDF2_HASH_ROUNDS);
- headerbuf.append('\n');
-
- // line 8: IV of the user key [hex]
- Cipher mkC = Cipher.getInstance("AES/CBC/PKCS5Padding");
- mkC.init(Cipher.ENCRYPT_MODE, userKey);
-
- byte[] IV = mkC.getIV();
- headerbuf.append(byteArrayToHex(IV));
- headerbuf.append('\n');
-
- // line 9: master IV + key blob, encrypted by the user key [hex]. Blob format:
- // [byte] IV length = Niv
- // [array of Niv bytes] IV itself
- // [byte] master key length = Nmk
- // [array of Nmk bytes] master key itself
- // [byte] MK checksum hash length = Nck
- // [array of Nck bytes] master key checksum hash
- //
- // The checksum is the (master key + checksum salt), run through the
- // stated number of PBKDF2 rounds
- IV = c.getIV();
- byte[] mk = masterKeySpec.getEncoded();
- byte[] checksum = makeKeyChecksum(PBKDF_CURRENT, masterKeySpec.getEncoded(),
- checksumSalt, PBKDF2_HASH_ROUNDS);
-
- ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
- + checksum.length + 3);
- DataOutputStream mkOut = new DataOutputStream(blob);
- mkOut.writeByte(IV.length);
- mkOut.write(IV);
- mkOut.writeByte(mk.length);
- mkOut.write(mk);
- mkOut.writeByte(checksum.length);
- mkOut.write(checksum);
- mkOut.flush();
- byte[] encryptedMk = mkC.doFinal(blob.toByteArray());
- headerbuf.append(byteArrayToHex(encryptedMk));
- headerbuf.append('\n');
-
- return finalOutput;
- }
-
- private void backupOnePackage(PackageInfo pkg, OutputStream out)
- throws RemoteException {
+ public int backupOnePackage(PackageInfo pkg) throws RemoteException {
+ int result = BackupTransport.TRANSPORT_OK;
Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName);
IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
@@ -3162,47 +2849,52 @@
byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(pkg.packageName,
UserHandle.USER_OWNER);
- sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
final int token = generateToken();
FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1],
token, sendApk, !isSharedStorage, widgetBlob);
pipes[1].close(); // the runner has dup'd it
pipes[1] = null;
- Thread t = new Thread(runner);
+ Thread t = new Thread(runner, "app-data-runner");
t.start();
- // Now pull data from the app and stuff it into the compressor
+ // Now pull data from the app and stuff it into the output
try {
- routeSocketDataToOutput(pipes[0], out);
+ routeSocketDataToOutput(pipes[0], mOutput);
} catch (IOException e) {
Slog.i(TAG, "Caught exception reading from agent", e);
+ result = BackupTransport.AGENT_ERROR;
}
if (!waitUntilOperationComplete(token)) {
Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
+ result = BackupTransport.AGENT_ERROR;
} else {
if (DEBUG) Slog.d(TAG, "Full package backup success: " + pkg.packageName);
}
} catch (IOException e) {
Slog.e(TAG, "Error backing up " + pkg.packageName, e);
+ result = BackupTransport.AGENT_ERROR;
} finally {
try {
// flush after every package
- out.flush();
+ mOutput.flush();
if (pipes != null) {
if (pipes[0] != null) pipes[0].close();
if (pipes[1] != null) pipes[1].close();
}
} catch (IOException e) {
Slog.w(TAG, "Error bringing down backup stack");
+ result = BackupTransport.TRANSPORT_ERROR;
}
}
} else {
Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName);
+ result = BackupTransport.AGENT_ERROR;
}
tearDown(pkg);
+ return result;
}
private void writeApkToBackup(PackageInfo pkg, BackupDataOutput output) {
@@ -3232,16 +2924,6 @@
}
}
- private void finalizeBackup(OutputStream out) {
- try {
- // A standard 'tar' EOF sequence: two 512-byte blocks of all zeroes.
- byte[] eof = new byte[512 * 2]; // newly allocated == zero filled
- out.write(eof);
- } catch (IOException e) {
- Slog.w(TAG, "Error attempting to finalize backup stream");
- }
- }
-
private void writeAppManifest(PackageInfo pkg, File manifestFile,
boolean withApk, boolean withWidgets) throws IOException {
// Manifest format. All data are strings ending in LF:
@@ -3332,7 +3014,7 @@
if (MORE_DEBUG) Slog.d(TAG, "Backup complete, killing host process");
mActivityManager.killApplicationProcess(app.processName, app.uid);
} else {
- if (MORE_DEBUG) Slog.d(TAG, "Not killing after restore: " + app.processName);
+ if (MORE_DEBUG) Slog.d(TAG, "Not killing after backup: " + app.processName);
}
} catch (RemoteException e) {
Slog.d(TAG, "Lost app trying to shut down");
@@ -3340,9 +3022,18 @@
}
}
}
+ }
+
+ // Generic driver skeleton for full backup operations
+ abstract class FullBackupTask implements Runnable {
+ IFullBackupRestoreObserver mObserver;
+
+ FullBackupTask(IFullBackupRestoreObserver observer) {
+ mObserver = observer;
+ }
// wrappers for observer use
- void sendStartBackup() {
+ final void sendStartBackup() {
if (mObserver != null) {
try {
mObserver.onStartBackup();
@@ -3353,7 +3044,7 @@
}
}
- void sendOnBackupPackage(String name) {
+ final void sendOnBackupPackage(String name) {
if (mObserver != null) {
try {
// TODO: use a more user-friendly name string
@@ -3365,7 +3056,7 @@
}
}
- void sendEndBackup() {
+ final void sendEndBackup() {
if (mObserver != null) {
try {
mObserver.onEndBackup();
@@ -3377,6 +3068,556 @@
}
}
+ // Full backup task variant used for adb backup
+ class PerformAdbBackupTask extends FullBackupTask {
+ FullBackupEngine mBackupEngine;
+ final AtomicBoolean mLatch;
+
+ ParcelFileDescriptor mOutputFile;
+ DeflaterOutputStream mDeflater;
+ boolean mIncludeApks;
+ boolean mIncludeObbs;
+ boolean mIncludeShared;
+ boolean mDoWidgets;
+ boolean mAllApps;
+ boolean mIncludeSystem;
+ boolean mCompress;
+ ArrayList<String> mPackages;
+ String mCurrentPassword;
+ String mEncryptPassword;
+
+ PerformAdbBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer,
+ boolean includeApks, boolean includeObbs, boolean includeShared,
+ boolean doWidgets, String curPassword, String encryptPassword, boolean doAllApps,
+ boolean doSystem, boolean doCompress, String[] packages, AtomicBoolean latch) {
+ super(observer);
+ mLatch = latch;
+
+ mOutputFile = fd;
+ mIncludeApks = includeApks;
+ mIncludeObbs = includeObbs;
+ mIncludeShared = includeShared;
+ mDoWidgets = doWidgets;
+ mAllApps = doAllApps;
+ mIncludeSystem = doSystem;
+ mPackages = (packages == null)
+ ? new ArrayList<String>()
+ : new ArrayList<String>(Arrays.asList(packages));
+ mCurrentPassword = curPassword;
+ // when backing up, if there is a current backup password, we require that
+ // the user use a nonempty encryption password as well. if one is supplied
+ // in the UI we use that, but if the UI was left empty we fall back to the
+ // current backup password (which was supplied by the user as well).
+ if (encryptPassword == null || "".equals(encryptPassword)) {
+ mEncryptPassword = curPassword;
+ } else {
+ mEncryptPassword = encryptPassword;
+ }
+ mCompress = doCompress;
+ }
+
+ void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) {
+ for (String pkgName : pkgNames) {
+ if (!set.containsKey(pkgName)) {
+ try {
+ PackageInfo info = mPackageManager.getPackageInfo(pkgName,
+ PackageManager.GET_SIGNATURES);
+ set.put(pkgName, info);
+ } catch (NameNotFoundException e) {
+ Slog.w(TAG, "Unknown package " + pkgName + ", skipping");
+ }
+ }
+ }
+ }
+
+ private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
+ OutputStream ofstream) throws Exception {
+ // User key will be used to encrypt the master key.
+ byte[] newUserSalt = randomBytes(PBKDF2_SALT_SIZE);
+ SecretKey userKey = buildPasswordKey(PBKDF_CURRENT, mEncryptPassword, newUserSalt,
+ PBKDF2_HASH_ROUNDS);
+
+ // the master key is random for each backup
+ byte[] masterPw = new byte[256 / 8];
+ mRng.nextBytes(masterPw);
+ byte[] checksumSalt = randomBytes(PBKDF2_SALT_SIZE);
+
+ // primary encryption of the datastream with the random key
+ Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES");
+ c.init(Cipher.ENCRYPT_MODE, masterKeySpec);
+ OutputStream finalOutput = new CipherOutputStream(ofstream, c);
+
+ // line 4: name of encryption algorithm
+ headerbuf.append(ENCRYPTION_ALGORITHM_NAME);
+ headerbuf.append('\n');
+ // line 5: user password salt [hex]
+ headerbuf.append(byteArrayToHex(newUserSalt));
+ headerbuf.append('\n');
+ // line 6: master key checksum salt [hex]
+ headerbuf.append(byteArrayToHex(checksumSalt));
+ headerbuf.append('\n');
+ // line 7: number of PBKDF2 rounds used [decimal]
+ headerbuf.append(PBKDF2_HASH_ROUNDS);
+ headerbuf.append('\n');
+
+ // line 8: IV of the user key [hex]
+ Cipher mkC = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ mkC.init(Cipher.ENCRYPT_MODE, userKey);
+
+ byte[] IV = mkC.getIV();
+ headerbuf.append(byteArrayToHex(IV));
+ headerbuf.append('\n');
+
+ // line 9: master IV + key blob, encrypted by the user key [hex]. Blob format:
+ // [byte] IV length = Niv
+ // [array of Niv bytes] IV itself
+ // [byte] master key length = Nmk
+ // [array of Nmk bytes] master key itself
+ // [byte] MK checksum hash length = Nck
+ // [array of Nck bytes] master key checksum hash
+ //
+ // The checksum is the (master key + checksum salt), run through the
+ // stated number of PBKDF2 rounds
+ IV = c.getIV();
+ byte[] mk = masterKeySpec.getEncoded();
+ byte[] checksum = makeKeyChecksum(PBKDF_CURRENT, masterKeySpec.getEncoded(),
+ checksumSalt, PBKDF2_HASH_ROUNDS);
+
+ ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
+ + checksum.length + 3);
+ DataOutputStream mkOut = new DataOutputStream(blob);
+ mkOut.writeByte(IV.length);
+ mkOut.write(IV);
+ mkOut.writeByte(mk.length);
+ mkOut.write(mk);
+ mkOut.writeByte(checksum.length);
+ mkOut.write(checksum);
+ mkOut.flush();
+ byte[] encryptedMk = mkC.doFinal(blob.toByteArray());
+ headerbuf.append(byteArrayToHex(encryptedMk));
+ headerbuf.append('\n');
+
+ return finalOutput;
+ }
+
+ private void finalizeBackup(OutputStream out) {
+ try {
+ // A standard 'tar' EOF sequence: two 512-byte blocks of all zeroes.
+ byte[] eof = new byte[512 * 2]; // newly allocated == zero filled
+ out.write(eof);
+ } catch (IOException e) {
+ Slog.w(TAG, "Error attempting to finalize backup stream");
+ }
+ }
+
+ @Override
+ public void run() {
+ Slog.i(TAG, "--- Performing full-dataset adb backup ---");
+
+ TreeMap<String, PackageInfo> packagesToBackup = new TreeMap<String, PackageInfo>();
+ FullBackupObbConnection obbConnection = new FullBackupObbConnection();
+ obbConnection.establish(); // we'll want this later
+
+ sendStartBackup();
+
+ // doAllApps supersedes the package set if any
+ if (mAllApps) {
+ List<PackageInfo> allPackages = mPackageManager.getInstalledPackages(
+ PackageManager.GET_SIGNATURES);
+ for (int i = 0; i < allPackages.size(); i++) {
+ PackageInfo pkg = allPackages.get(i);
+ // Exclude system apps if we've been asked to do so
+ if (mIncludeSystem == true
+ || ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
+ packagesToBackup.put(pkg.packageName, pkg);
+ }
+ }
+ }
+
+ // If we're doing widget state as well, ensure that we have all the involved
+ // host & provider packages in the set
+ if (mDoWidgets) {
+ List<String> pkgs =
+ AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_OWNER);
+ if (pkgs != null) {
+ if (MORE_DEBUG) {
+ Slog.i(TAG, "Adding widget participants to backup set:");
+ StringBuilder sb = new StringBuilder(128);
+ sb.append(" ");
+ for (String s : pkgs) {
+ sb.append(' ');
+ sb.append(s);
+ }
+ Slog.i(TAG, sb.toString());
+ }
+ addPackagesToSet(packagesToBackup, pkgs);
+ }
+ }
+
+ // Now process the command line argument packages, if any. Note that explicitly-
+ // named system-partition packages will be included even if includeSystem was
+ // set to false.
+ if (mPackages != null) {
+ addPackagesToSet(packagesToBackup, mPackages);
+ }
+
+ // Now we cull any inapplicable / inappropriate packages from the set
+ Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator();
+ while (iter.hasNext()) {
+ PackageInfo pkg = iter.next().getValue();
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0
+ || pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
+ // Cull any packages that have indicated that backups are not permitted, as well
+ // as any explicit mention of the 'special' shared-storage agent package (we
+ // handle that one at the end).
+ iter.remove();
+ } else if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
+ && (pkg.applicationInfo.backupAgentName == null)) {
+ // Cull any packages that run as system-domain uids but do not define their
+ // own backup agents
+ if (MORE_DEBUG) {
+ Slog.i(TAG, "... ignoring non-agent system package " + pkg.packageName);
+ }
+ iter.remove();
+ }
+ }
+
+ // flatten the set of packages now so we can explicitly control the ordering
+ ArrayList<PackageInfo> backupQueue =
+ new ArrayList<PackageInfo>(packagesToBackup.values());
+ FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor());
+ OutputStream out = null;
+
+ PackageInfo pkg = null;
+ try {
+ boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
+ OutputStream finalOutput = ofstream;
+
+ // Verify that the given password matches the currently-active
+ // backup password, if any
+ if (!backupPasswordMatches(mCurrentPassword)) {
+ if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
+ return;
+ }
+
+ // Write the global file header. All strings are UTF-8 encoded; lines end
+ // with a '\n' byte. Actual backup data begins immediately following the
+ // final '\n'.
+ //
+ // line 1: "ANDROID BACKUP"
+ // line 2: backup file format version, currently "2"
+ // line 3: compressed? "0" if not compressed, "1" if compressed.
+ // line 4: name of encryption algorithm [currently only "none" or "AES-256"]
+ //
+ // When line 4 is not "none", then additional header data follows:
+ //
+ // line 5: user password salt [hex]
+ // line 6: master key checksum salt [hex]
+ // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
+ // line 8: IV of the user key [hex]
+ // line 9: master key blob [hex]
+ // IV of the master key, master key itself, master key checksum hash
+ //
+ // The master key checksum is the master key plus its checksum salt, run through
+ // 10k rounds of PBKDF2. This is used to verify that the user has supplied the
+ // correct password for decrypting the archive: the master key decrypted from
+ // the archive using the user-supplied password is also run through PBKDF2 in
+ // this way, and if the result does not match the checksum as stored in the
+ // archive, then we know that the user-supplied password does not match the
+ // archive's.
+ StringBuilder headerbuf = new StringBuilder(1024);
+
+ headerbuf.append(BACKUP_FILE_HEADER_MAGIC);
+ headerbuf.append(BACKUP_FILE_VERSION); // integer, no trailing \n
+ headerbuf.append(mCompress ? "\n1\n" : "\n0\n");
+
+ try {
+ // Set up the encryption stage if appropriate, and emit the correct header
+ if (encrypting) {
+ finalOutput = emitAesBackupHeader(headerbuf, finalOutput);
+ } else {
+ headerbuf.append("none\n");
+ }
+
+ byte[] header = headerbuf.toString().getBytes("UTF-8");
+ ofstream.write(header);
+
+ // Set up the compression stage feeding into the encryption stage (if any)
+ if (mCompress) {
+ Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
+ finalOutput = new DeflaterOutputStream(finalOutput, deflater, true);
+ }
+
+ out = finalOutput;
+ } catch (Exception e) {
+ // Should never happen!
+ Slog.e(TAG, "Unable to emit archive header", e);
+ return;
+ }
+
+ // Shared storage if requested
+ if (mIncludeShared) {
+ try {
+ pkg = mPackageManager.getPackageInfo(SHARED_BACKUP_AGENT_PACKAGE, 0);
+ backupQueue.add(pkg);
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "Unable to find shared-storage backup handler");
+ }
+ }
+
+ // Now actually run the constructed backup sequence
+ int N = backupQueue.size();
+ for (int i = 0; i < N; i++) {
+ pkg = backupQueue.get(i);
+ final boolean isSharedStorage =
+ pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
+
+ mBackupEngine = new FullBackupEngine(out, pkg.packageName, mIncludeApks);
+ sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
+ mBackupEngine.backupOnePackage(pkg);
+
+ // after the app's agent runs to handle its private filesystem
+ // contents, back up any OBB content it has on its behalf.
+ if (mIncludeObbs) {
+ boolean obbOkay = obbConnection.backupObbs(pkg, out);
+ if (!obbOkay) {
+ throw new RuntimeException("Failure writing OBB stack for " + pkg);
+ }
+ }
+ }
+
+ // Done!
+ finalizeBackup(out);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "App died during full backup");
+ } catch (Exception e) {
+ Slog.e(TAG, "Internal exception during full backup", e);
+ } finally {
+ try {
+ if (out != null) out.close();
+ mOutputFile.close();
+ } catch (IOException e) {
+ /* nothing we can do about this */
+ }
+ synchronized (mCurrentOpLock) {
+ mCurrentOperations.clear();
+ }
+ synchronized (mLatch) {
+ mLatch.set(true);
+ mLatch.notifyAll();
+ }
+ sendEndBackup();
+ obbConnection.tearDown();
+ if (DEBUG) Slog.d(TAG, "Full backup pass complete.");
+ mWakelock.release();
+ }
+ }
+ }
+
+ // Full backup task extension used for transport-oriented operation
+ class PerformFullTransportBackupTask extends FullBackupTask {
+ static final String TAG = "PFTBT";
+ ArrayList<PackageInfo> mPackages;
+ AtomicBoolean mLatch;
+
+ PerformFullTransportBackupTask(IFullBackupRestoreObserver observer,
+ String[] whichPackages, AtomicBoolean latch) {
+ super(observer);
+ mLatch = latch;
+ mPackages = new ArrayList<PackageInfo>(whichPackages.length);
+
+ for (String pkg : whichPackages) {
+ try {
+ PackageInfo info = mPackageManager.getPackageInfo(pkg,
+ PackageManager.GET_SIGNATURES);
+ if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0
+ || pkg.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
+ // Cull any packages that have indicated that backups are not permitted,
+ // as well as any explicit mention of the 'special' shared-storage agent
+ // package (we handle that one at the end).
+ if (MORE_DEBUG) {
+ Slog.d(TAG, "Ignoring opted-out package " + pkg);
+ }
+ continue;
+ } else if ((info.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
+ && (info.applicationInfo.backupAgentName == null)) {
+ // Cull any packages that run as system-domain uids but do not define their
+ // own backup agents
+ if (MORE_DEBUG) {
+ Slog.d(TAG, "Ignoring non-agent system package " + pkg);
+ }
+ continue;
+ }
+ mPackages.add(info);
+ } catch (NameNotFoundException e) {
+ Slog.i(TAG, "Requested package " + pkg + " not found; ignoring");
+ }
+ }
+ }
+
+ @Override
+ public void run() {
+ IBackupTransport transport = getTransport(mCurrentTransport);
+ if (transport == null) {
+ Slog.w(TAG, "Transport not present; full data backup not performed");
+ return;
+ }
+
+ // data from the app, passed to us for bridging to the transport
+ ParcelFileDescriptor[] enginePipes = null;
+
+ // Pipe through which we write data to the transport
+ ParcelFileDescriptor[] transportPipes = null;
+
+ try {
+ // Set up to send data to the transport
+ if (transport != null) {
+ for (PackageInfo target : mPackages) {
+ if (DEBUG) {
+ Slog.i(TAG, "Initiating full-data transport backup of "
+ + target.packageName);
+ }
+ transportPipes = ParcelFileDescriptor.createPipe();
+
+ // Tell the transport the data's coming
+ int result = transport.performFullBackup(target, transportPipes[0]);
+ if (result == BackupTransport.TRANSPORT_OK) {
+ // The transport has its own copy of the read end of the pipe,
+ // so close ours now
+ transportPipes[0].close();
+ transportPipes[0] = null;
+
+ // Now set up the backup engine / data source end of things
+ enginePipes = ParcelFileDescriptor.createPipe();
+ AtomicBoolean runnerLatch = new AtomicBoolean(false);
+ SinglePackageBackupRunner backupRunner =
+ new SinglePackageBackupRunner(enginePipes[1], target,
+ runnerLatch);
+ // The runner dup'd the pipe half, so we close it here
+ enginePipes[1].close();
+ enginePipes[1] = null;
+
+ // Spin off the runner to fetch the app's data and pipe it
+ // into the engine pipes
+ (new Thread(backupRunner, "package-backup-bridge")).start();
+
+ // Read data off the engine pipe and pass it to the transport
+ // pipe until we hit EOD on the input stream.
+ FileInputStream in = new FileInputStream(
+ enginePipes[0].getFileDescriptor());
+ FileOutputStream out = new FileOutputStream(
+ transportPipes[1].getFileDescriptor());
+ byte[] buffer = new byte[8192];
+ int nRead = 0;
+ do {
+ nRead = in.read(buffer);
+ if (nRead > 0) {
+ out.write(buffer, 0, nRead);
+ result = transport.sendBackupData(nRead);
+ }
+ } while (nRead > 0 && result == BackupTransport.TRANSPORT_OK);
+
+ // Done -- how did it turn out?
+ if (result == BackupTransport.TRANSPORT_OK){
+ result = transport.finishBackup();
+ } else {
+ Slog.w(TAG, "Error backing up " + target.packageName);
+ }
+ } else if (result == BackupTransport.TRANSPORT_PACKAGE_REJECTED) {
+ if (DEBUG) {
+ Slog.i(TAG, "Transport rejected backup of " + target.packageName
+ + ", skipping");
+ }
+ // do nothing, clean up, and continue looping
+ } else {
+ if (DEBUG) {
+ Slog.i(TAG, "Transport failed; aborting backup");
+ return;
+ }
+ }
+ cleanUpPipes(transportPipes);
+ cleanUpPipes(enginePipes);
+ }
+
+ if (DEBUG) {
+ Slog.i(TAG, "Full backup completed.");
+ }
+ }
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception trying full transport backup", e);
+ } finally {
+ cleanUpPipes(transportPipes);
+ cleanUpPipes(enginePipes);
+ synchronized (mLatch) {
+ mLatch.set(true);
+ mLatch.notifyAll();
+ }
+ }
+ }
+
+ void cleanUpPipes(ParcelFileDescriptor[] pipes) {
+ if (pipes != null) {
+ if (pipes[0] != null) {
+ ParcelFileDescriptor fd = pipes[0];
+ pipes[0] = null;
+ try {
+ fd.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Unable to close pipe!");
+ }
+ }
+ if (pipes[1] != null) {
+ ParcelFileDescriptor fd = pipes[1];
+ pipes[1] = null;
+ try {
+ fd.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Unable to close pipe!");
+ }
+ }
+ }
+ }
+
+ // Run the backup and pipe it back to the given socket -- expects to run on
+ // a standalone thread. The runner owns this half of the pipe, and closes
+ // it to indicate EOD to the other end.
+ class SinglePackageBackupRunner implements Runnable {
+ final ParcelFileDescriptor mOutput;
+ final PackageInfo mTarget;
+ final AtomicBoolean mLatch;
+
+ SinglePackageBackupRunner(ParcelFileDescriptor output, PackageInfo target,
+ AtomicBoolean latch) throws IOException {
+ int oldfd = output.getFd();
+ mOutput = ParcelFileDescriptor.dup(output.getFileDescriptor());
+ mTarget = target;
+ mLatch = latch;
+ }
+
+ @Override
+ public void run() {
+ try {
+ FileOutputStream out = new FileOutputStream(mOutput.getFileDescriptor());
+ FullBackupEngine engine = new FullBackupEngine(out, mTarget.packageName, false);
+ engine.backupOnePackage(mTarget);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception during full package backup of " + mTarget);
+ } finally {
+ synchronized (mLatch) {
+ mLatch.set(true);
+ mLatch.notifyAll();
+ }
+ try {
+ mOutput.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Error closing transport pipe in runner");
+ }
+ }
+ }
+
+ }
+ }
// ----- Full restore from a file/socket -----
@@ -3410,7 +3651,7 @@
ACCEPT_IF_APK
}
- class PerformFullRestoreTask extends ObbServiceClient implements Runnable {
+ class PerformFullRestoreTask implements Runnable {
ParcelFileDescriptor mInputFile;
String mCurrentPassword;
String mDecryptPassword;
@@ -3877,7 +4118,7 @@
Slog.d(TAG, "system process agent - spinning a thread");
RestoreFileRunnable runner = new RestoreFileRunnable(
mAgent, info, mPipes[0], token);
- new Thread(runner).start();
+ new Thread(runner, "restore-sys-runner").start();
} else {
mAgent.doRestoreFile(mPipes[0], info.size, info.type,
info.domain, info.path, info.mode, info.mtime,
@@ -4937,7 +5178,9 @@
void restorePmMetadata() {
try {
- String packageName = mTransport.nextRestorePackage();
+ RestoreDescription desc = mTransport.nextRestorePackage();
+ // TODO: handle full-data stream restore payloads
+ String packageName = desc.getPackageName();
if (packageName == null) {
Slog.e(TAG, "Error getting first restore package");
EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
@@ -5005,7 +5248,9 @@
void restoreNextAgent() {
try {
- String packageName = mTransport.nextRestorePackage();
+ final RestoreDescription desc = mTransport.nextRestorePackage();
+ // TODO: handle full-data stream restore payloads
+ String packageName = desc.getPackageName();
if (packageName == null) {
Slog.e(TAG, "Error getting next restore package");
@@ -5684,13 +5929,16 @@
return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0);
}
- // Run a *full* backup pass for the given package, writing the resulting data stream
+ // Run a *full* backup pass for the given packages, writing the resulting data stream
// to the supplied file descriptor. This method is synchronous and does not return
// to the caller until the backup has been completed.
+ //
+ // This is the variant used by 'adb backup'; it requires on-screen confirmation
+ // by the user because it can be used to offload data over untrusted USB.
@Override
public void fullBackup(ParcelFileDescriptor fd, boolean includeApks,
boolean includeObbs, boolean includeShared, boolean doWidgets,
- boolean doAllApps, boolean includeSystem, String[] pkgList) {
+ boolean doAllApps, boolean includeSystem, boolean compress, String[] pkgList) {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullBackup");
final int callingUserHandle = UserHandle.getCallingUserId();
@@ -5725,7 +5973,7 @@
Slog.i(TAG, "Beginning full backup...");
FullBackupParams params = new FullBackupParams(fd, includeApks, includeObbs,
- includeShared, doWidgets, doAllApps, includeSystem, pkgList);
+ includeShared, doWidgets, doAllApps, includeSystem, compress, pkgList);
final int token = generateToken();
synchronized (mFullConfirmations) {
mFullConfirmations.put(token, params);
@@ -5759,6 +6007,36 @@
}
}
+ @Override
+ public void fullTransportBackup(String[] pkgNames) {
+ mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
+ "fullTransportBackup");
+
+ final int callingUserHandle = UserHandle.getCallingUserId();
+ if (callingUserHandle != UserHandle.USER_OWNER) {
+ throw new IllegalStateException("Restore supported only for the device owner");
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "fullTransportBackup()");
+ }
+
+ AtomicBoolean latch = new AtomicBoolean(false);
+ PerformFullTransportBackupTask task = new PerformFullTransportBackupTask(null, pkgNames, latch);
+ (new Thread(task, "full-transport-master")).start();
+ synchronized (latch) {
+ try {
+ while (latch.get() == false) {
+ latch.wait();
+ }
+ } catch (InterruptedException e) {}
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "Done with full transport backup.");
+ }
+ }
+
+ @Override
public void fullRestore(ParcelFileDescriptor fd) {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullRestore");
@@ -5876,8 +6154,8 @@
if (allow) {
final int verb = params instanceof FullBackupParams
- ? MSG_RUN_FULL_BACKUP
- : MSG_RUN_FULL_RESTORE;
+ ? MSG_RUN_ADB_BACKUP
+ : MSG_RUN_ADB_RESTORE;
params.observer = observer;
params.curPassword = curPassword;
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index fe5c2ef..aeb195f 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.database.ContentObserver;
import android.os.BatteryStats;
import com.android.internal.app.IBatteryStats;
import com.android.server.am.BatteryStatsService;
@@ -149,8 +150,8 @@
com.android.internal.R.integer.config_criticalBatteryWarningLevel);
mLowBatteryWarningLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
- mLowBatteryCloseWarningLevel = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);
+ mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
mShutdownBatteryTemperature = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shutdownBatteryTemperature);
@@ -173,11 +174,39 @@
void systemReady() {
// check our power situation now that it is safe to display the shutdown dialog.
synchronized (mLock) {
- shutdownIfNoPowerLocked();
- shutdownIfOverTempLocked();
+ ContentObserver obs = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ synchronized (mLock) {
+ updateBatteryWarningLevelLocked();
+ }
+ }
+ };
+ final ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
+ false, obs, UserHandle.USER_ALL);
+ updateBatteryWarningLevelLocked();
}
}
+ void updateBatteryWarningLevelLocked() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ int defWarnLevel = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_lowBatteryWarningLevel);
+ mLowBatteryWarningLevel = Settings.Global.getInt(resolver,
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
+ if (mLowBatteryWarningLevel == 0) {
+ mLowBatteryWarningLevel = defWarnLevel;
+ }
+ if (mLowBatteryWarningLevel < mCriticalBatteryLevel) {
+ mLowBatteryWarningLevel = mCriticalBatteryLevel;
+ }
+ mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
+ processValuesLocked(true);
+ }
+
/**
* Returns true if the device is plugged into any of the specified plug types.
*/
@@ -232,7 +261,7 @@
}
}
- public boolean isBatteryLowLocked() {
+ public boolean shouldSendBatteryLowLocked() {
final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
@@ -299,14 +328,14 @@
if (!mUpdatesStopped) {
mBatteryProps = props;
// Process the new values.
- processValuesLocked();
+ processValuesLocked(false);
} else {
mLastBatteryProps.set(props);
}
}
}
- private void processValuesLocked() {
+ private void processValuesLocked(boolean force) {
boolean logOutlier = false;
long dischargeDuration = 0;
@@ -349,14 +378,14 @@
shutdownIfNoPowerLocked();
shutdownIfOverTempLocked();
- if (mBatteryProps.batteryStatus != mLastBatteryStatus ||
+ if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus ||
mBatteryProps.batteryHealth != mLastBatteryHealth ||
mBatteryProps.batteryPresent != mLastBatteryPresent ||
mBatteryProps.batteryLevel != mLastBatteryLevel ||
mPlugType != mLastPlugType ||
mBatteryProps.batteryVoltage != mLastBatteryVoltage ||
mBatteryProps.batteryTemperature != mLastBatteryTemperature ||
- mInvalidCharger != mLastInvalidCharger) {
+ mInvalidCharger != mLastInvalidCharger)) {
if (mPlugType != mLastPlugType) {
if (mLastPlugType == BATTERY_PLUGGED_NONE) {
@@ -400,7 +429,24 @@
logOutlier = true;
}
- mBatteryLevelLow = isBatteryLowLocked();
+ if (!mBatteryLevelLow) {
+ // Should we now switch in to low battery mode?
+ if (mPlugType == BATTERY_PLUGGED_NONE
+ && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel) {
+ mBatteryLevelLow = true;
+ }
+ } else {
+ // Should we now switch out of low battery mode?
+ if (mPlugType != BATTERY_PLUGGED_NONE) {
+ mBatteryLevelLow = false;
+ } else if (mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel) {
+ mBatteryLevelLow = false;
+ } else if (force && mBatteryProps.batteryLevel >= mLowBatteryWarningLevel) {
+ // If being forced, the previous state doesn't matter, we will just
+ // absolutely check to see if we are now above the warning level.
+ mBatteryLevelLow = false;
+ }
+ }
sendIntentLocked();
@@ -428,7 +474,7 @@
});
}
- if (mBatteryLevelLow) {
+ if (shouldSendBatteryLowLocked()) {
mSentLowBatteryBroadcast = true;
mHandler.post(new Runnable() {
@Override
@@ -650,7 +696,7 @@
long ident = Binder.clearCallingIdentity();
try {
mUpdatesStopped = true;
- processValuesLocked();
+ processValuesLocked(false);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -664,7 +710,7 @@
if (mUpdatesStopped) {
mUpdatesStopped = false;
mBatteryProps.set(mLastBatteryProps);
- processValuesLocked();
+ processValuesLocked(false);
}
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index e2a8ca2..07c9048 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -308,6 +308,10 @@
}
public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
+ if (callback == null) {
+ Log.w(TAG, "Callback is null in registerAdapter");
+ return null;
+ }
Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
msg.obj = callback;
mHandler.sendMessage(msg);
@@ -317,6 +321,10 @@
}
public void unregisterAdapter(IBluetoothManagerCallback callback) {
+ if (callback == null) {
+ Log.w(TAG, "Callback is null in unregisterAdapter");
+ return;
+ }
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
"Need BLUETOOTH permission");
Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index bd45761..00bda06 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -20,7 +20,6 @@
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
-import static android.net.ConnectivityManager.NetworkCallbackListener;
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
import static android.net.ConnectivityManager.TYPE_DUMMY;
import static android.net.ConnectivityManager.TYPE_MOBILE;
@@ -630,8 +629,8 @@
if (DBG) log("ConnectivityService starting up");
NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
mDefaultRequest = new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId());
NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(),
NetworkRequestInfo.REQUEST);
@@ -1669,7 +1668,7 @@
continue;
}
- int prefix = destination.getNetworkPrefixLength();
+ int prefix = destination.getPrefixLength();
InetAddress addrMasked = NetworkUtils.getNetworkPart(address, prefix);
InetAddress destMasked = NetworkUtils.getNetworkPart(destination.getAddress(),
prefix);
@@ -1871,7 +1870,7 @@
mNetd.addRoute(netId, r);
}
if (exempt) {
- LinkAddress dest = r.getDestination();
+ LinkAddress dest = r.getDestinationLinkAddress();
if (!mExemptAddresses.contains(dest)) {
mNetd.setHostExemption(dest);
mExemptAddresses.add(dest);
@@ -1904,7 +1903,7 @@
} else {
mNetd.removeRoute(netId, r);
}
- LinkAddress dest = r.getDestination();
+ LinkAddress dest = r.getDestinationLinkAddress();
if (mExemptAddresses.contains(dest)) {
mNetd.clearHostExemption(dest);
mExemptAddresses.remove(dest);
@@ -2691,7 +2690,7 @@
dnsDiff = curLp.compareDnses(newLp);
} else if (newLp != null) {
routeDiff.added = newLp.getAllRoutes();
- dnsDiff.added = newLp.getDnses();
+ dnsDiff.added = newLp.getDnsServers();
}
boolean routesChanged = (routeDiff.removed.size() != 0 || routeDiff.added.size() != 0);
@@ -2915,7 +2914,7 @@
if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
LinkProperties p = nt.getLinkProperties();
if (p == null) return;
- Collection<InetAddress> dnses = p.getDnses();
+ Collection<InetAddress> dnses = p.getDnsServers();
int netId = nt.getNetwork().netId;
if (mNetConfigs[netType].isDefault()) {
String network = nt.getNetworkInfo().getTypeName();
@@ -4438,7 +4437,9 @@
mIsProvisioningNetwork.set(true);
MobileDataStateTracker mdst = (MobileDataStateTracker)
mNetTrackers[ConnectivityManager.TYPE_MOBILE];
- mdst.setInternalDataEnable(false);
+
+ // Disable radio until user starts provisioning
+ mdst.setRadio(false);
} else {
if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url");
}
@@ -4950,17 +4951,24 @@
// Mark notification as not visible
setProvNotificationVisible(false, ConnectivityManager.TYPE_MOBILE_HIPRI, null, null);
- // If provisioning network handle as a special case,
+ // Check airplane mode
+ boolean isAirplaneModeOn = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
+ // If provisioning network and not in airplane mode handle as a special case,
// otherwise launch browser with the intent directly.
- if (mIsProvisioningNetwork.get()) {
+ if (mIsProvisioningNetwork.get() && !isAirplaneModeOn) {
if (DBG) log("handleMobileProvisioningAction: on prov network enable then launch");
+ mIsProvisioningNetwork.set(false);
// mIsStartingProvisioning.set(true);
// MobileDataStateTracker mdst = (MobileDataStateTracker)
// mNetTrackers[ConnectivityManager.TYPE_MOBILE];
+ // Radio was disabled on CMP_RESULT_CODE_PROVISIONING_NETWORK, enable it here
+// mdst.setRadio(true);
// mdst.setEnableFailFastMobileData(DctConstants.ENABLED);
// mdst.enableMobileProvisioning(url);
} else {
if (DBG) log("handleMobileProvisioningAction: not prov network");
+ mIsProvisioningNetwork.set(false);
// Check for apps that can handle provisioning first
Intent provisioningIntent = new Intent(TelephonyIntents.ACTION_CARRIER_SETUP);
provisioningIntent.addCategory(TelephonyIntents.CATEGORY_MCCMNC_PREFIX
@@ -5401,7 +5409,7 @@
@Override
public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
- Messenger messenger, int timeoutSec, IBinder binder, int legacyType) {
+ Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
== false) {
enforceConnectivityInternalPermission();
@@ -5409,7 +5417,7 @@
enforceChangePermission();
}
- if (timeoutSec < 0 || timeoutSec > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_SEC) {
+ if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) {
throw new IllegalArgumentException("Bad timeout specified");
}
NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
@@ -5419,9 +5427,9 @@
NetworkRequestInfo.REQUEST);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
- if (timeoutSec > 0) {
+ if (timeoutMs > 0) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST,
- nri), timeoutSec * 1000);
+ nri), timeoutMs);
}
return networkRequest;
}
@@ -5625,7 +5633,7 @@
}
private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) {
if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) {
- Collection<InetAddress> dnses = newLp.getDnses();
+ Collection<InetAddress> dnses = newLp.getDnsServers();
if (dnses.size() == 0 && mDefaultDns != null) {
dnses = new ArrayList();
dnses.add(mDefaultDns);
@@ -5685,7 +5693,7 @@
int a2 = 0;
switch (notificationType) {
case ConnectivityManager.CALLBACK_LOSING:
- a1 = 30; // TODO - read this from NetworkMonitor
+ a1 = 30 * 1000; // TODO - read this from NetworkMonitor
// fall through
case ConnectivityManager.CALLBACK_PRECHECK:
case ConnectivityManager.CALLBACK_AVAILABLE:
@@ -5790,7 +5798,8 @@
isNewDefault = true;
updateActiveDefaultNetwork(newNetwork);
if (newNetwork.linkProperties != null) {
- setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnses());
+ setDefaultDnsSystemProperties(
+ newNetwork.linkProperties.getDnsServers());
} else {
setDefaultDnsSystemProperties(new ArrayList<InetAddress>());
}
diff --git a/services/core/java/com/android/server/IdleMaintenanceService.java b/services/core/java/com/android/server/IdleMaintenanceService.java
deleted file mode 100644
index acc6abe..0000000
--- a/services/core/java/com/android/server/IdleMaintenanceService.java
+++ /dev/null
@@ -1,818 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.maintenance.IIdleCallback;
-import android.app.maintenance.IIdleService;
-import android.app.maintenance.IdleService;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.WorkSource;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Random;
-
-/**
- * This service observes the device state and when applicable sends
- * broadcasts at the beginning and at the end of a period during which
- * observers can perform idle maintenance tasks. Typical use of the
- * idle maintenance is to perform somehow expensive tasks that can be
- * postponed to a moment when they will not degrade user experience.
- *
- * The current implementation is very simple. The start of a maintenance
- * window is announced if: the screen is off or showing a dream AND the
- * battery level is more than twenty percent AND at least one hour passed
- * activity).
- *
- * The end of a maintenance window is announced only if: a start was
- * announced AND the screen turned on or a dream was stopped.
- *
- * Method naming note:
- * Methods whose name ends with "Tm" must only be called from the main thread.
- */
-public class IdleMaintenanceService extends BroadcastReceiver {
-
- private static final boolean DEBUG = false;
-
- private static final String TAG = IdleMaintenanceService.class.getSimpleName();
-
- private static final int LAST_USER_ACTIVITY_TIME_INVALID = -1;
-
- private static final long MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS = 24 * 60 * 60 * 1000; // 1 day
-
- private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING = 30; // percent
-
- private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING = 80; // percent
-
- private static final int MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING = 20; // percent
-
- private static final long MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START = 71 * 60 * 1000; // 71 min
-
- private static final long MAX_IDLE_MAINTENANCE_DURATION = 71 * 60 * 1000; // 71 min
-
- private static final String ACTION_UPDATE_IDLE_MAINTENANCE_STATE =
- "com.android.server.IdleMaintenanceService.action.UPDATE_IDLE_MAINTENANCE_STATE";
-
- private static final String ACTION_FORCE_IDLE_MAINTENANCE =
- "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE";
-
- static final int MSG_OP_COMPLETE = 1;
- static final int MSG_IDLE_FINISHED = 2;
- static final int MSG_TIMEOUT = 3;
-
- // when a timeout happened, what were we expecting?
- static final int VERB_BINDING = 1;
- static final int VERB_IDLING = 2;
- static final int VERB_ENDING = 3;
-
- // What are our relevant timeouts / allocated slices?
- static final long OP_TIMEOUT = 8 * 1000; // 8 seconds to bind or ack the start
- static final long IDLE_TIMESLICE = 10 * 60 * 1000; // ten minutes for each idler
-
- private final AlarmManager mAlarmService;
- private final BatteryService mBatteryService;
- private final PendingIntent mUpdateIdleMaintenanceStatePendingIntent;
- private final Context mContext;
- private final WakeLock mWakeLock;
- private final WorkSource mSystemWorkSource = new WorkSource(Process.myUid());
-
- private long mLastIdleMaintenanceStartTimeMillis;
- private long mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID;
- private boolean mIdleMaintenanceStarted;
-
- final IdleCallback mCallback;
- final Handler mHandler;
-
- final Random mTokenGenerator = new Random();
-
- int makeToken() {
- int token;
- do {
- token = mTokenGenerator.nextInt(Integer.MAX_VALUE);
- } while (token == 0);
- return token;
- }
-
- class ActiveTask {
- public IdleServiceInfo who;
- public int verb;
- public int token;
-
- ActiveTask(IdleServiceInfo target, int action) {
- who = target;
- verb = action;
- token = makeToken();
- }
-
- @Override
- public String toString() {
- return "ActiveTask{" + Integer.toHexString(this.hashCode())
- + " : verb=" + verb
- + " : token=" + token
- + " : "+ who + "}";
- }
- }
-
- // What operations are in flight?
- final SparseArray<ActiveTask> mPendingOperations = new SparseArray<ActiveTask>();
-
- // Idle service queue management
- class IdleServiceInfo {
- public final ComponentName componentName;
- public final int uid;
- public IIdleService service;
-
- IdleServiceInfo(ResolveInfo info, ComponentName cname) {
- componentName = cname; // derived from 'info' but this avoids an extra object
- uid = info.serviceInfo.applicationInfo.uid;
- service = null;
- }
-
- @Override
- public int hashCode() {
- return componentName.hashCode();
- }
-
- @Override
- public String toString() {
- return "IdleServiceInfo{" + componentName
- + " / " + (service == null ? "null" : service.asBinder()) + "}";
- }
- }
-
- final ArrayMap<ComponentName, IdleServiceInfo> mIdleServices =
- new ArrayMap<ComponentName, IdleServiceInfo>();
- final LinkedList<IdleServiceInfo> mIdleServiceQueue = new LinkedList<IdleServiceInfo>();
- IdleServiceInfo mCurrentIdler; // set when we've committed to launching an idler
- IdleServiceInfo mLastIdler; // end of queue when idling begins
-
- void reportNoTimeout(int token, boolean result) {
- final Message msg = mHandler.obtainMessage(MSG_OP_COMPLETE, result ? 1 : 0, token);
- mHandler.sendMessage(msg);
- }
-
- // Binder acknowledgment trampoline
- class IdleCallback extends IIdleCallback.Stub {
- @Override
- public void acknowledgeStart(int token, boolean result) throws RemoteException {
- reportNoTimeout(token, result);
- }
-
- @Override
- public void acknowledgeStop(int token) throws RemoteException {
- reportNoTimeout(token, false);
- }
-
- @Override
- public void idleFinished(int token) throws RemoteException {
- if (DEBUG) {
- Slog.v(TAG, "idleFinished: " + token);
- }
- final Message msg = mHandler.obtainMessage(MSG_IDLE_FINISHED, 0, token);
- mHandler.sendMessage(msg);
- }
- }
-
- // Stuff that we run on a Handler
- class IdleHandler extends Handler {
- public IdleHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- final int token = msg.arg2;
-
- switch (msg.what) {
- case MSG_OP_COMPLETE: {
- if (DEBUG) {
- Slog.i(TAG, "MSG_OP_COMPLETE of " + token);
- }
- ActiveTask task = mPendingOperations.get(token);
- if (task != null) {
- mPendingOperations.remove(token);
- removeMessages(MSG_TIMEOUT);
-
- handleOpCompleteTm(task, msg.arg1);
- } else {
- // Can happen in a race between timeout and actual
- // (belated) completion of a "begin idling" or similar
- // operation. In that state we've already processed the
- // timeout, so we intentionally no-op here.
- if (DEBUG) {
- Slog.w(TAG, "Belated op-complete of " + token);
- }
- }
- break;
- }
-
- case MSG_IDLE_FINISHED: {
- if (DEBUG) {
- Slog.i(TAG, "MSG_IDLE_FINISHED of " + token);
- }
- ActiveTask task = mPendingOperations.get(token);
- if (task != null) {
- if (DEBUG) {
- Slog.i(TAG, "... removing task " + token);
- }
- mPendingOperations.remove(token);
- removeMessages(MSG_TIMEOUT);
-
- handleIdleFinishedTm(task);
- } else {
- // Can happen "legitimately" from an app explicitly calling
- // idleFinished() after already having been told that its slice
- // has ended.
- if (DEBUG) {
- Slog.w(TAG, "Belated idle-finished of " + token);
- }
- }
- break;
- }
-
- case MSG_TIMEOUT: {
- if (DEBUG) {
- Slog.i(TAG, "MSG_TIMEOUT of " + token);
- }
- ActiveTask task = mPendingOperations.get(token);
- if (task != null) {
- mPendingOperations.remove(token);
- removeMessages(MSG_OP_COMPLETE);
-
- handleTimeoutTm(task);
- } else {
- // This one should not happen; we flushed timeout messages
- // whenever we entered a state after which we have established
- // that they are not appropriate.
- Slog.w(TAG, "Unexpected timeout of " + token);
- }
- break;
- }
-
- default:
- Slog.w(TAG, "Unknown message: " + msg.what);
- }
- }
- }
-
- void handleTimeoutTm(ActiveTask task) {
- switch (task.verb) {
- case VERB_BINDING: {
- // We were trying to bind to this service, but it wedged or otherwise
- // failed to respond in time. Let it stay in the queue for the next
- // time around, but just give up on it for now and go on to the next.
- startNextIdleServiceTm();
- break;
- }
- case VERB_IDLING: {
- // The service has reached the end of its designated idle timeslice.
- // This is not considered an error.
- if (DEBUG) {
- Slog.i(TAG, "Idler reached end of timeslice: " + task.who);
- }
- sendEndIdleTm(task.who);
- break;
- }
- case VERB_ENDING: {
- if (mCurrentIdler == task.who) {
- if (DEBUG) {
- Slog.i(TAG, "Task timed out when ending; unbind needed");
- }
- handleIdleFinishedTm(task);
- } else {
- if (DEBUG) {
- Slog.w(TAG, "Ending timeout for non-current idle service!");
- }
- }
- break;
- }
- default: {
- Slog.w(TAG, "Unknown timeout state " + task.verb);
- break;
- }
- }
- }
-
- void handleOpCompleteTm(ActiveTask task, int result) {
- if (DEBUG) {
- Slog.i(TAG, "handleOpComplete : task=" + task + " result=" + result);
- }
- if (task.verb == VERB_IDLING) {
- // If the service was told to begin idling and responded positively, then
- // it has begun idling and will eventually either explicitly finish, or
- // reach the end of its allotted timeslice. It's running free now, so we
- // just schedule the idle-expiration timeout under the token it's already been
- // given and let it keep going.
- if (result != 0) {
- scheduleOpTimeoutTm(task);
- } else {
- // The idle service has indicated that it does not, in fact,
- // need to run at present, so we immediately indicate that it's
- // to finish idling, and go on to the next idler.
- if (DEBUG) {
- Slog.i(TAG, "Idler declined idling; moving along");
- }
- sendEndIdleTm(task.who);
- }
- } else {
- // In the idling case, the task will be cleared either as the result of a timeout
- // or of an explicit idleFinished(). For all other operations (binding, ending) we
- // are done with the task as such, so we remove it from our bookkeeping.
- if (DEBUG) {
- Slog.i(TAG, "Clearing task " + task);
- }
- mPendingOperations.remove(task.token);
- if (task.verb == VERB_ENDING) {
- // The last bit of handshaking around idle cessation for this target
- handleIdleFinishedTm(task);
- }
- }
- }
-
- void handleIdleFinishedTm(ActiveTask task) {
- final IdleServiceInfo who = task.who;
- if (who == mCurrentIdler) {
- if (DEBUG) {
- Slog.i(TAG, "Current idler has finished: " + who);
- Slog.i(TAG, "Attributing wakelock to system work source");
- }
- mContext.unbindService(mConnection);
- startNextIdleServiceTm();
- } else {
- Slog.w(TAG, "finish from non-current idle service? " + who);
- }
- }
-
- void updateIdleServiceQueueTm() {
- if (DEBUG) {
- Slog.i(TAG, "Updating idle service queue");
- }
- PackageManager pm = mContext.getPackageManager();
- Intent idleIntent = new Intent(IdleService.SERVICE_INTERFACE);
- List<ResolveInfo> services = pm.queryIntentServices(idleIntent, 0);
- for (ResolveInfo info : services) {
- if (info.serviceInfo != null) {
- if (IdleService.PERMISSION_BIND.equals(info.serviceInfo.permission)) {
- final ComponentName componentName = new ComponentName(
- info.serviceInfo.packageName,
- info.serviceInfo.name);
- if (DEBUG) {
- Slog.i(TAG, " - " + componentName);
- }
- if (!mIdleServices.containsKey(componentName)) {
- if (DEBUG) {
- Slog.i(TAG, " + not known; adding");
- }
- IdleServiceInfo serviceInfo = new IdleServiceInfo(info, componentName);
- mIdleServices.put(componentName, serviceInfo);
- mIdleServiceQueue.add(serviceInfo);
- }
- } else {
- if (DEBUG) {
- Slog.i(TAG, "Idle service " + info.serviceInfo
- + " does not have required permission; ignoring");
- }
- }
- }
- }
- }
-
- void startNextIdleServiceTm() {
- mWakeLock.setWorkSource(mSystemWorkSource);
-
- if (mLastIdler == null) {
- // we've run the queue; nothing more to do until the next idle interval.
- if (DEBUG) {
- Slog.i(TAG, "Queue already drained; nothing more to do");
- }
- return;
- }
-
- if (DEBUG) {
- Slog.i(TAG, "startNextIdleService : last=" + mLastIdler + " cur=" + mCurrentIdler);
- if (mIdleServiceQueue.size() > 0) {
- int i = 0;
- Slog.i(TAG, "Queue (" + mIdleServiceQueue.size() + "):");
- for (IdleServiceInfo info : mIdleServiceQueue) {
- Slog.i(TAG, " " + i + " : " + info);
- i++;
- }
- }
- }
- if (mCurrentIdler != mLastIdler) {
- if (mIdleServiceQueue.size() > 0) {
- IdleServiceInfo target = mIdleServiceQueue.pop();
- if (DEBUG) {
- Slog.i(TAG, "starting next idle service " + target);
- }
- Intent idleIntent = new Intent(IdleService.SERVICE_INTERFACE);
- idleIntent.setComponent(target.componentName);
- mCurrentIdler = target;
- ActiveTask task = new ActiveTask(target, VERB_BINDING);
- scheduleOpTimeoutTm(task);
- boolean bindOk = mContext.bindServiceAsUser(idleIntent, mConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY, UserHandle.OWNER);
- if (!bindOk) {
- if (DEBUG) {
- Slog.w(TAG, "bindService() to " + target.componentName
- + " failed");
- }
- } else {
- mIdleServiceQueue.add(target); // at the end for next time
- if (DEBUG) { Slog.i(TAG, "Attributing wakelock to target uid " + target.uid); }
- mWakeLock.setWorkSource(new WorkSource(target.uid));
- }
- } else {
- // Queue is empty but mLastIdler is non-null -- eeep. Clear *everything*
- // and wind up until the next time around.
- Slog.e(TAG, "Queue unexpectedly empty; resetting. last="
- + mLastIdler + " cur=" + mCurrentIdler);
- mHandler.removeMessages(MSG_TIMEOUT);
- mPendingOperations.clear();
- stopIdleMaintenanceTm();
- }
- } else {
- // we've reached the place we started, so mark the queue as drained
- if (DEBUG) {
- Slog.i(TAG, "Reached end of queue.");
- }
- stopIdleMaintenanceTm();
- }
- }
-
- void sendStartIdleTm(IdleServiceInfo who) {
- ActiveTask task = new ActiveTask(who, VERB_IDLING);
- scheduleOpTimeoutTm(task);
- try {
- who.service.startIdleMaintenance(mCallback, task.token);
- } catch (RemoteException e) {
- // We bound to it, but now we can't reach it. Bail and go on to the
- // next service.
- mContext.unbindService(mConnection);
- if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
- mHandler.removeMessages(MSG_TIMEOUT);
- startNextIdleServiceTm();
- }
- }
-
- void sendEndIdleTm(IdleServiceInfo who) {
- ActiveTask task = new ActiveTask(who, VERB_ENDING);
- scheduleOpTimeoutTm(task);
- if (DEBUG) {
- Slog.i(TAG, "Sending end-idle to " + who);
- }
- try {
- who.service.stopIdleMaintenance(mCallback, task.token);
- } catch (RemoteException e) {
- // We bound to it, but now we can't reach it. Bail and go on to the
- // next service.
- mContext.unbindService(mConnection);
- if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
- mHandler.removeMessages(MSG_TIMEOUT);
- startNextIdleServiceTm();
- }
- }
-
- ServiceConnection mConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG) {
- Slog.i(TAG, "onServiceConnected(" + name + ")");
- }
- IdleServiceInfo info = mIdleServices.get(name);
- if (info != null) {
- // Bound! Cancel the bind timeout
- mHandler.removeMessages(MSG_TIMEOUT);
- // Now tell it to start its idle work
- info.service = IIdleService.Stub.asInterface(service);
- sendStartIdleTm(info);
- } else {
- // We bound to a service we don't know about. That's ungood.
- Slog.e(TAG, "Connected to unexpected component " + name);
- mContext.unbindService(this);
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) {
- Slog.i(TAG, "onServiceDisconnected(" + name + ")");
- }
- IdleServiceInfo who = mIdleServices.get(name);
- if (who == mCurrentIdler) {
- // Hm, okay; they didn't tell us they were finished but they
- // went away. Crashed, probably. Oh well. They're gone, so
- // we can't finish them cleanly; just force things along.
- Slog.w(TAG, "Idler unexpectedly vanished: " + mCurrentIdler);
- mContext.unbindService(this);
- mHandler.removeMessages(MSG_TIMEOUT);
- startNextIdleServiceTm();
- } else {
- // Not the current idler, so we don't interrupt our process...
- if (DEBUG) {
- Slog.w(TAG, "Disconnect of abandoned or unexpected service " + name);
- }
- }
- }
- };
-
- // Schedules a timeout / end-of-work based on the task verb
- void scheduleOpTimeoutTm(ActiveTask task) {
- final long timeoutMillis = (task.verb == VERB_IDLING) ? IDLE_TIMESLICE : OP_TIMEOUT;
- if (DEBUG) {
- Slog.i(TAG, "Scheduling timeout (token " + task.token
- + " : verb " + task.verb + ") for " + task + " in " + timeoutMillis);
- }
- mPendingOperations.put(task.token, task);
- mHandler.removeMessages(MSG_TIMEOUT);
- final Message msg = mHandler.obtainMessage(MSG_TIMEOUT, 0, task.token);
- mHandler.sendMessageDelayed(msg, timeoutMillis);
- }
-
- // -------------------------------------------------------------------------------
- public IdleMaintenanceService(Context context, BatteryService batteryService) {
- mContext = context;
- mBatteryService = batteryService;
-
- mAlarmService = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-
- PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-
- mHandler = new IdleHandler(mContext.getMainLooper());
- mCallback = new IdleCallback();
-
- Intent intent = new Intent(ACTION_UPDATE_IDLE_MAINTENANCE_STATE);
- intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mUpdateIdleMaintenanceStatePendingIntent = PendingIntent.getBroadcast(mContext, 0,
- intent, PendingIntent.FLAG_UPDATE_CURRENT);
-
- register(mHandler);
- }
-
- public void register(Handler handler) {
- IntentFilter intentFilter = new IntentFilter();
-
- // Alarm actions.
- intentFilter.addAction(ACTION_UPDATE_IDLE_MAINTENANCE_STATE);
-
- // Battery actions.
- intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
-
- // Screen actions.
- intentFilter.addAction(Intent.ACTION_SCREEN_ON);
- intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
-
- // Dream actions.
- intentFilter.addAction(Intent.ACTION_DREAMING_STARTED);
- intentFilter.addAction(Intent.ACTION_DREAMING_STOPPED);
-
- mContext.registerReceiverAsUser(this, UserHandle.ALL,
- intentFilter, null, mHandler);
-
- intentFilter = new IntentFilter();
- intentFilter.addAction(ACTION_FORCE_IDLE_MAINTENANCE);
- mContext.registerReceiverAsUser(this, UserHandle.ALL,
- intentFilter, android.Manifest.permission.SET_ACTIVITY_WATCHER, mHandler);
- }
-
- private void scheduleUpdateIdleMaintenanceState(long delayMillis) {
- final long triggetRealTimeMillis = SystemClock.elapsedRealtime() + delayMillis;
- mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggetRealTimeMillis,
- mUpdateIdleMaintenanceStatePendingIntent);
- }
-
- private void unscheduleUpdateIdleMaintenanceState() {
- mAlarmService.cancel(mUpdateIdleMaintenanceStatePendingIntent);
- }
-
- private void updateIdleMaintenanceStateTm(boolean noisy) {
- if (mIdleMaintenanceStarted) {
- // Idle maintenance can be interrupted by user activity, or duration
- // time out, or low battery.
- final boolean batteryOk
- = batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning();
- if (!lastUserActivityPermitsIdleMaintenanceRunning() || !batteryOk) {
- unscheduleUpdateIdleMaintenanceState();
- mIdleMaintenanceStarted = false;
- // We stopped since we don't have enough battery or timed out but the
- // user is not using the device, so we should be able to run maintenance
- // in the next maintenance window since the battery may be charged
- // without interaction and the min interval between maintenances passed.
- if (!batteryOk) {
- scheduleUpdateIdleMaintenanceState(
- getNextIdleMaintenanceIntervalStartFromNow());
- }
-
- EventLogTags.writeIdleMaintenanceWindowFinish(SystemClock.elapsedRealtime(),
- mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(),
- isBatteryCharging() ? 1 : 0);
- scheduleIdleFinishTm();
- }
- } else if (deviceStatePermitsIdleMaintenanceStart(noisy)
- && lastUserActivityPermitsIdleMaintenanceStart(noisy)
- && lastRunPermitsIdleMaintenanceStart(noisy)) {
- // Now that we started idle maintenance, we should schedule another
- // update for the moment when the idle maintenance times out.
- scheduleUpdateIdleMaintenanceState(MAX_IDLE_MAINTENANCE_DURATION);
- mIdleMaintenanceStarted = true;
- EventLogTags.writeIdleMaintenanceWindowStart(SystemClock.elapsedRealtime(),
- mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(),
- isBatteryCharging() ? 1 : 0);
- mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime();
- startIdleMaintenanceTm();
- } else if (lastUserActivityPermitsIdleMaintenanceStart(noisy)) {
- if (lastRunPermitsIdleMaintenanceStart(noisy)) {
- // The user does not use the device and we did not run maintenance in more
- // than the min interval between runs, so schedule an update - maybe the
- // battery will be charged latter.
- scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
- } else {
- // The user does not use the device but we have run maintenance in the min
- // interval between runs, so schedule an update after the min interval ends.
- scheduleUpdateIdleMaintenanceState(
- getNextIdleMaintenanceIntervalStartFromNow());
- }
- }
- }
-
- void startIdleMaintenanceTm() {
- if (DEBUG) {
- Slog.i(TAG, "*** Starting idle maintenance ***");
- }
- if (DEBUG) { Slog.i(TAG, "Attributing wakelock to system work source"); }
- mWakeLock.setWorkSource(mSystemWorkSource);
- mWakeLock.acquire();
- updateIdleServiceQueueTm();
- mCurrentIdler = null;
- mLastIdler = (mIdleServiceQueue.size() > 0) ? mIdleServiceQueue.peekLast() : null;
- startNextIdleServiceTm();
- }
-
- // Start a graceful wind-down of the idle maintenance state: end the current idler
- // and pretend that we've finished running the queue. If there's no current idler,
- // this is a no-op.
- void scheduleIdleFinishTm() {
- if (mCurrentIdler != null) {
- if (DEBUG) {
- Slog.i(TAG, "*** Finishing idle maintenance ***");
- }
- mLastIdler = mCurrentIdler;
- sendEndIdleTm(mCurrentIdler);
- } else {
- if (DEBUG) {
- Slog.w(TAG, "Asked to finish idle maintenance but we're done already");
- }
- }
- }
-
- // Actual finalization of the idle maintenance sequence
- void stopIdleMaintenanceTm() {
- if (mLastIdler != null) {
- if (DEBUG) {
- Slog.i(TAG, "*** Idle maintenance shutdown ***");
- }
- mWakeLock.setWorkSource(mSystemWorkSource);
- mLastIdler = mCurrentIdler = null;
- updateIdleMaintenanceStateTm(false); // resets 'started' and schedules next window
- mWakeLock.release();
- } else {
- Slog.e(TAG, "ERROR: idle shutdown but invariants not held. last=" + mLastIdler
- + " cur=" + mCurrentIdler + " size=" + mIdleServiceQueue.size());
- }
- }
-
- private long getNextIdleMaintenanceIntervalStartFromNow() {
- return mLastIdleMaintenanceStartTimeMillis + MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS
- - SystemClock.elapsedRealtime();
- }
-
- private boolean deviceStatePermitsIdleMaintenanceStart(boolean noisy) {
- final int minBatteryLevel = isBatteryCharging()
- ? MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_CHARGING
- : MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_START_NOT_CHARGING;
- boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
- && mBatteryService.getBatteryLevel() > minBatteryLevel);
- if (!allowed && noisy) {
- Slog.i("IdleMaintenance", "Idle maintenance not allowed due to power");
- }
- return allowed;
- }
-
- private boolean lastUserActivityPermitsIdleMaintenanceStart(boolean noisy) {
- // The last time the user poked the device is above the threshold.
- boolean allowed = (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID
- && SystemClock.elapsedRealtime() - mLastUserActivityElapsedTimeMillis
- > MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
- if (!allowed && noisy) {
- Slog.i("IdleMaintenance", "Idle maintenance not allowed due to last user activity");
- }
- return allowed;
- }
-
- private boolean lastRunPermitsIdleMaintenanceStart(boolean noisy) {
- // Enough time passed since the last maintenance run.
- boolean allowed = SystemClock.elapsedRealtime() - mLastIdleMaintenanceStartTimeMillis
- > MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
- if (!allowed && noisy) {
- Slog.i("IdleMaintenance", "Idle maintenance not allowed due time since last");
- }
- return allowed;
- }
-
- private boolean lastUserActivityPermitsIdleMaintenanceRunning() {
- // The user is not using the device.
- return (mLastUserActivityElapsedTimeMillis != LAST_USER_ACTIVITY_TIME_INVALID);
- }
-
- private boolean batteryLevelAndMaintenanceTimeoutPermitsIdleMaintenanceRunning() {
- // Battery not too low and the maintenance duration did not timeout.
- return (mBatteryService.getBatteryLevel() > MIN_BATTERY_LEVEL_IDLE_MAINTENANCE_RUNNING
- && mLastIdleMaintenanceStartTimeMillis + MAX_IDLE_MAINTENANCE_DURATION
- > SystemClock.elapsedRealtime());
- }
-
- private boolean isBatteryCharging() {
- return mBatteryService.getPlugType() > 0
- && mBatteryService.getInvalidCharger() == 0;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) {
- Log.i(TAG, intent.getAction());
- }
- String action = intent.getAction();
- if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
- // We care about battery only if maintenance is in progress so we can
- // stop it if battery is too low. Note that here we assume that the
- // maintenance clients are properly holding a wake lock. We will
- // refactor the maintenance to use services instead of intents for the
- // next release. The only client for this for now is internal an holds
- // a wake lock correctly.
- if (mIdleMaintenanceStarted) {
- updateIdleMaintenanceStateTm(false);
- }
- } else if (Intent.ACTION_SCREEN_ON.equals(action)
- || Intent.ACTION_DREAMING_STOPPED.equals(action)) {
- mLastUserActivityElapsedTimeMillis = LAST_USER_ACTIVITY_TIME_INVALID;
- // Unschedule any future updates since we already know that maintenance
- // cannot be performed since the user is back.
- unscheduleUpdateIdleMaintenanceState();
- // If the screen went on/stopped dreaming, we know the user is using the
- // device which means that idle maintenance should be stopped if running.
- updateIdleMaintenanceStateTm(false);
- } else if (Intent.ACTION_SCREEN_OFF.equals(action)
- || Intent.ACTION_DREAMING_STARTED.equals(action)) {
- mLastUserActivityElapsedTimeMillis = SystemClock.elapsedRealtime();
- // If screen went off/started dreaming, we may be able to start idle maintenance
- // after the minimal user inactivity elapses. We schedule an alarm for when
- // this timeout elapses since the device may go to sleep by then.
- scheduleUpdateIdleMaintenanceState(MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START);
- } else if (ACTION_UPDATE_IDLE_MAINTENANCE_STATE.equals(action)) {
- updateIdleMaintenanceStateTm(false);
- } else if (ACTION_FORCE_IDLE_MAINTENANCE.equals(action)) {
- long now = SystemClock.elapsedRealtime() - 1;
- mLastUserActivityElapsedTimeMillis = now - MIN_USER_INACTIVITY_IDLE_MAINTENANCE_START;
- mLastIdleMaintenanceStartTimeMillis = now - MIN_IDLE_MAINTENANCE_INTERVAL_MILLIS;
- updateIdleMaintenanceStateTm(true);
- }
- }
-}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 251247c..8fb2e9f 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -149,6 +149,7 @@
static final int MSG_BIND_METHOD = 3010;
static final int MSG_SET_ACTIVE = 3020;
static final int MSG_SET_CURSOR_ANCHOR_MONITOR_MODE = 3030;
+ static final int MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER = 3040;
static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
@@ -172,7 +173,7 @@
private final HardKeyboardListener mHardKeyboardListener;
private final WindowManagerService mWindowManagerService;
- final InputBindResult mNoBinding = new InputBindResult(null, null, null, -1);
+ final InputBindResult mNoBinding = new InputBindResult(null, null, null, -1, -1);
// All known input methods. mMethodMap also serves as the global
// lock for this class.
@@ -379,6 +380,8 @@
*/
boolean mScreenOn = true;
+ int mCurUserActionNotificationSequenceNumber = 0;
+
int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
int mImeWindowVis;
@@ -1129,7 +1132,8 @@
showCurrentInputLocked(getAppShowFlags(), null);
}
return new InputBindResult(session.session,
- session.channel != null ? session.channel.dup() : null, mCurId, mCurSeq);
+ (session.channel != null ? session.channel.dup() : null),
+ mCurId, mCurSeq, mCurUserActionNotificationSequenceNumber);
}
InputBindResult startInputLocked(IInputMethodClient client,
@@ -1205,7 +1209,8 @@
// Return to client, and we will get back with it when
// we have had a session made for it.
requestClientSessionLocked(cs);
- return new InputBindResult(null, null, mCurId, mCurSeq);
+ return new InputBindResult(null, null, mCurId, mCurSeq,
+ mCurUserActionNotificationSequenceNumber);
} else if (SystemClock.uptimeMillis()
< (mLastBindTime+TIME_TO_RECONNECT)) {
// In this case we have connected to the service, but
@@ -1215,7 +1220,8 @@
// we can report back. If it has been too long, we want
// to fall through so we can try a disconnect/reconnect
// to see if we can get back in touch with the service.
- return new InputBindResult(null, null, mCurId, mCurSeq);
+ return new InputBindResult(null, null, mCurId, mCurSeq,
+ mCurUserActionNotificationSequenceNumber);
} else {
EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
@@ -1234,7 +1240,8 @@
if (!mSystemReady) {
// If the system is not yet ready, we shouldn't be running third
// party code.
- return new InputBindResult(null, null, mCurMethodId, mCurSeq);
+ return new InputBindResult(null, null, mCurMethodId, mCurSeq,
+ mCurUserActionNotificationSequenceNumber);
}
InputMethodInfo info = mMethodMap.get(mCurMethodId);
@@ -1263,7 +1270,8 @@
WindowManager.LayoutParams.TYPE_INPUT_METHOD);
} catch (RemoteException e) {
}
- return new InputBindResult(null, null, mCurId, mCurSeq);
+ return new InputBindResult(null, null, mCurId, mCurSeq,
+ mCurUserActionNotificationSequenceNumber);
} else {
mCurIntent = null;
Slog.w(TAG, "Failure connecting to input method service: "
@@ -2310,11 +2318,19 @@
}
@Override
- public void notifyUserAction() {
+ public void notifyUserAction(int sequenceNumber) {
if (DEBUG) {
- Slog.d(TAG, "Got the notification of a user action");
+ Slog.d(TAG, "Got the notification of a user action. sequenceNumber:" + sequenceNumber);
}
synchronized (mMethodMap) {
+ if (mCurUserActionNotificationSequenceNumber != sequenceNumber) {
+ if (DEBUG) {
+ Slog.d(TAG, "Ignoring the user action notification due to the sequence number "
+ + "mismatch. expected:" + mCurUserActionNotificationSequenceNumber
+ + " actual: " + sequenceNumber);
+ }
+ return;
+ }
final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
if (imi != null) {
mSwitchingController.onUserActionLocked(imi, mCurrentSubtype);
@@ -2588,6 +2604,20 @@
+ " uid " + ((ClientState)msg.obj).uid);
}
return true;
+ case MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER: {
+ final int sequenceNumber = msg.arg1;
+ final IInputMethodClient client = (IInputMethodClient)msg.obj;
+ try {
+ client.setUserActionNotificationSequenceNumber(sequenceNumber);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Got RemoteException sending "
+ + "setUserActionNotificationSequenceNumber("
+ + sequenceNumber + ") notification to pid "
+ + ((ClientState)msg.obj).pid + " uid "
+ + ((ClientState)msg.obj).uid);
+ }
+ return true;
+ }
// --------------------------------------------------------------
case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
@@ -2999,6 +3029,19 @@
// Update the history of InputMethod and Subtype
mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
+ mCurUserActionNotificationSequenceNumber =
+ Math.max(mCurUserActionNotificationSequenceNumber + 1, 1);
+ if (DEBUG) {
+ Slog.d(TAG, "Bump mCurUserActionNotificationSequenceNumber:"
+ + mCurUserActionNotificationSequenceNumber);
+ }
+
+ if (mCurClient != null && mCurClient.client != null) {
+ executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
+ MSG_SET_USER_ACTION_NOTIFICATION_SEQUENCE_NUMBER,
+ mCurUserActionNotificationSequenceNumber, mCurClient.client));
+ }
+
// Set Subtype here
if (imi == null || subtypeId < 0) {
mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
@@ -3490,6 +3533,8 @@
+ " mShowExplicitlyRequested=" + mShowExplicitlyRequested
+ " mShowForced=" + mShowForced
+ " mInputShown=" + mInputShown);
+ p.println(" mCurUserActionNotificationSequenceNumber="
+ + mCurUserActionNotificationSequenceNumber);
p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mScreenOn);
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 98fa522..10382ba 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -29,6 +29,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.location.Address;
@@ -55,10 +56,12 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.UserManager;
import android.os.WorkSource;
import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
+
import com.android.internal.content.PackageMonitor;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
@@ -144,6 +147,7 @@
private GeofenceManager mGeofenceManager;
private PackageManager mPackageManager;
private PowerManager mPowerManager;
+ private UserManager mUserManager;
private GeocoderProxy mGeocodeProvider;
private IGpsStatusProvider mGpsStatusProvider;
private INetInitiatedListener mNetInitiatedListener;
@@ -197,6 +201,7 @@
// current active user on the device - other users are denied location data
private int mCurrentUserId = UserHandle.USER_OWNER;
+ private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_OWNER };
public LocationManagerService(Context context) {
super();
@@ -241,6 +246,9 @@
};
mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
+ mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ updateUserProfiles(mCurrentUserId);
+
// prepare providers
loadProvidersLocked();
updateProvidersLocked();
@@ -262,6 +270,8 @@
// listen for user change
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+ intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
@@ -269,11 +279,46 @@
String action = intent.getAction();
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+ } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
+ || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
+ updateUserProfiles(mCurrentUserId);
}
}
}, UserHandle.ALL, intentFilter, null, mLocationHandler);
}
+ /**
+ * Makes a list of userids that are related to the current user. This is
+ * relevant when using managed profiles. Otherwise the list only contains
+ * the current user.
+ *
+ * @param currentUserId the current user, who might have an alter-ego.
+ */
+ void updateUserProfiles(int currentUserId) {
+ List<UserInfo> profiles = mUserManager.getProfiles(currentUserId);
+ synchronized (mLock) {
+ mCurrentUserProfiles = new int[profiles.size()];
+ for (int i = 0; i < mCurrentUserProfiles.length; i++) {
+ mCurrentUserProfiles[i] = profiles.get(i).id;
+ }
+ }
+ }
+
+ /**
+ * Checks if the specified userId matches any of the current foreground
+ * users stored in mCurrentUserProfiles.
+ */
+ private boolean isCurrentProfile(int userId) {
+ synchronized (mLock) {
+ for (int i = 0; i < mCurrentUserProfiles.length; i++) {
+ if (mCurrentUserProfiles[i] == userId) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
PackageManager pm = mContext.getPackageManager();
String systemPackageName = mContext.getPackageName();
@@ -434,8 +479,8 @@
mContext,
mLocationHandler,
flpHardwareProvider.getLocationHardware(),
- com.android.internal.R.bool.config_enableFusedLocationOverlay,
- com.android.internal.R.string.config_fusedLocationProviderPackageName,
+ com.android.internal.R.bool.config_enableHardwareFlpOverlay,
+ com.android.internal.R.string.config_hardwareFlpPackageName,
com.android.internal.R.array.config_locationProviderPackageNames);
if(fusedProxy == null) {
Slog.e(TAG, "Unable to bind FusedProxy.");
@@ -492,9 +537,10 @@
mLastLocation.clear();
mLastLocationCoarseInterval.clear();
for (LocationProviderInterface p : mProviders) {
- updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
+ updateProviderListenersLocked(p.getName(), false);
}
mCurrentUserId = userId;
+ updateUserProfiles(userId);
updateProvidersLocked();
}
}
@@ -894,7 +940,7 @@
* @return
*/
private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
- if (UserHandle.getUserId(uid) != mCurrentUserId && !isUidALocationProvider(uid)) {
+ if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
return false;
}
return isAllowedByCurrentUserSettingsLocked(provider);
@@ -1181,7 +1227,7 @@
String name = p.getName();
boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
if (isEnabled && !shouldBeEnabled) {
- updateProviderListenersLocked(name, false, mCurrentUserId);
+ updateProviderListenersLocked(name, false);
// If any provider has been disabled, clear all last locations for all providers.
// This is to be on the safe side in case a provider has location derived from
// this disabled provider.
@@ -1189,7 +1235,7 @@
mLastLocationCoarseInterval.clear();
changesMade = true;
} else if (!isEnabled && shouldBeEnabled) {
- updateProviderListenersLocked(name, true, mCurrentUserId);
+ updateProviderListenersLocked(name, true);
changesMade = true;
}
}
@@ -1201,7 +1247,7 @@
}
}
- private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
+ private void updateProviderListenersLocked(String provider, boolean enabled) {
int listeners = 0;
LocationProviderInterface p = mProvidersByName.get(provider);
@@ -1214,7 +1260,7 @@
final int N = records.size();
for (int i = 0; i < N; i++) {
UpdateRecord record = records.get(i);
- if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
+ if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
// Sends a notification message to the receiver
if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
if (deadReceivers == null) {
@@ -1253,7 +1299,7 @@
if (records != null) {
for (UpdateRecord record : records) {
- if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
+ if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
record.mReceiver.mAllowedResolutionLevel)) {
LocationRequest locationRequest = record.mRequest;
@@ -1274,7 +1320,7 @@
// under that threshold.
long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
for (UpdateRecord record : records) {
- if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
+ if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
LocationRequest locationRequest = record.mRequest;
if (locationRequest.getInterval() <= thresholdInterval) {
if (record.mReceiver.mWorkSource != null
@@ -2018,7 +2064,7 @@
boolean receiverDead = false;
int receiverUserId = UserHandle.getUserId(receiver.mUid);
- if (receiverUserId != mCurrentUserId && !isUidALocationProvider(receiver.mUid)) {
+ if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
if (D) {
Log.d(TAG, "skipping loc update for background user " + receiverUserId +
" (current user: " + mCurrentUserId + ", app: " +
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index d31fb60..39410c2 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -629,6 +629,11 @@
sendUmsIntent(true);
mSendUmsConnectedOnBoot = false;
}
+
+ /*
+ * Start scheduling nominally-daily fstrim operations
+ */
+ MountServiceIdler.scheduleIdlePass(mContext);
}
private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java
index 8b19321..215d92d 100644
--- a/services/core/java/com/android/server/MountServiceIdler.java
+++ b/services/core/java/com/android/server/MountServiceIdler.java
@@ -16,34 +16,93 @@
package com.android.server;
-import android.app.maintenance.IdleService;
+import java.util.Calendar;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
import android.util.Slog;
-public class MountServiceIdler extends IdleService {
+public class MountServiceIdler extends JobService {
private static final String TAG = "MountServiceIdler";
+ private static ComponentName sIdleService =
+ new ComponentName("android", MountServiceIdler.class.getName());
+
+ private static int MOUNT_JOB_ID = 808;
+
+ private boolean mStarted;
+ private JobParameters mJobParams;
private Runnable mFinishCallback = new Runnable() {
@Override
public void run() {
Slog.i(TAG, "Got mount service completion callback");
- finishIdle();
+ synchronized (mFinishCallback) {
+ if (mStarted) {
+ jobFinished(mJobParams, false);
+ mStarted = false;
+ }
+ }
+ // ... and try again tomorrow
+ scheduleIdlePass(MountServiceIdler.this);
}
};
@Override
- public boolean onIdleStart() {
+ public boolean onStartJob(JobParameters params) {
// The mount service will run an fstrim operation asynchronously
// on a designated separate thread, so we provide it with a callback
// that lets us cleanly end our idle timeslice. It's safe to call
// finishIdle() from any thread.
+ mJobParams = params;
MountService ms = MountService.sSelf;
if (ms != null) {
+ synchronized (mFinishCallback) {
+ mStarted = true;
+ }
ms.runIdleMaintenance(mFinishCallback);
}
return ms != null;
}
@Override
- public void onIdleStop() {
+ public boolean onStopJob(JobParameters params) {
+ // Once we kick off the fstrim we aren't actually interruptible; just note
+ // that we don't need to call jobFinished(), and let everything happen in
+ // the callback from the mount service.
+ synchronized (mFinishCallback) {
+ mStarted = false;
+ }
+ return false;
+ }
+
+ /**
+ * Schedule the idle job that will ping the mount service
+ */
+ public static void scheduleIdlePass(Context context) {
+ JobScheduler tm = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+
+ Calendar calendar = tomorrowMidnight();
+ final long timeToMidnight = calendar.getTimeInMillis() - System.currentTimeMillis();
+
+ JobInfo.Builder builder = new JobInfo.Builder(MOUNT_JOB_ID, sIdleService);
+ builder.setRequiresDeviceIdle(true);
+ builder.setRequiresCharging(true);
+ builder.setMinimumLatency(timeToMidnight);
+ tm.schedule(builder.build());
+ }
+
+ private static Calendar tomorrowMidnight() {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(System.currentTimeMillis());
+ calendar.set(Calendar.HOUR, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+ calendar.add(Calendar.DAY_OF_MONTH, 1);
+ return calendar;
}
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index eefe8da..7022294 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -41,6 +41,7 @@
import android.net.ConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.InterfaceConfiguration;
+import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.NetworkStats;
import android.net.NetworkUtils;
@@ -61,6 +62,7 @@
import android.os.SystemProperties;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionManager;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -144,6 +146,7 @@
public static final int InterfaceClassActivity = 613;
public static final int InterfaceAddressChange = 614;
public static final int InterfaceDnsServerInfo = 615;
+ public static final int RouteChange = 616;
}
static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
@@ -237,7 +240,9 @@
mThread = new Thread(mConnector, NETD_TAG);
mDaemonHandler = new Handler(FgThread.get().getLooper());
- mPhoneStateListener = new PhoneStateListener(mDaemonHandler.getLooper()) {
+ mPhoneStateListener = new PhoneStateListener(
+ SubscriptionManager.DEFAULT_SUB_ID, // FIXME: What Subscription should be used??
+ mDaemonHandler.getLooper()) {
public void onDataConnectionRealTimeInfoChanged(
DataConnectionRealTimeInfo dcRtInfo) {
notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE,
@@ -577,6 +582,28 @@
}
}
+ /**
+ * Notify our observers of a route change.
+ */
+ private void notifyRouteChange(String action, RouteInfo route) {
+ final int length = mObservers.beginBroadcast();
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ if (action.equals("updated")) {
+ mObservers.getBroadcastItem(i).routeUpdated(route);
+ } else {
+ mObservers.getBroadcastItem(i).routeRemoved(route);
+ }
+ } catch (RemoteException e) {
+ } catch (RuntimeException e) {
+ }
+ }
+ } finally {
+ mObservers.finishBroadcast();
+ }
+ }
+
//
// Netd Callback handling
//
@@ -719,6 +746,47 @@
}
return true;
// break;
+ case NetdResponseCode.RouteChange:
+ /*
+ * A route has been updated or removed.
+ * Format: "NNN Route <updated|removed> <dst> [via <gateway] [dev <iface>]"
+ */
+ if (!cooked[1].equals("Route") || cooked.length < 6) {
+ throw new IllegalStateException(errorMessage);
+ }
+
+ String via = null;
+ String dev = null;
+ boolean valid = true;
+ for (int i = 4; (i + 1) < cooked.length && valid; i += 2) {
+ if (cooked[i].equals("dev")) {
+ if (dev == null) {
+ dev = cooked[i+1];
+ } else {
+ valid = false; // Duplicate interface.
+ }
+ } else if (cooked[i].equals("via")) {
+ if (via == null) {
+ via = cooked[i+1];
+ } else {
+ valid = false; // Duplicate gateway.
+ }
+ } else {
+ valid = false; // Unknown syntax.
+ }
+ }
+ if (valid) {
+ try {
+ // InetAddress.parseNumericAddress(null) inexplicably returns ::1.
+ InetAddress gateway = null;
+ if (via != null) gateway = InetAddress.parseNumericAddress(via);
+ RouteInfo route = new RouteInfo(new IpPrefix(cooked[3]), gateway, dev);
+ notifyRouteChange(cooked[2], route);
+ return true;
+ } catch (IllegalArgumentException e) {}
+ }
+ throw new IllegalStateException(errorMessage);
+ // break;
default: break;
}
return false;
@@ -795,7 +863,7 @@
final Command cmd = new Command("interface", "setcfg", iface,
linkAddr.getAddress().getHostAddress(),
- linkAddr.getNetworkPrefixLength());
+ linkAddr.getPrefixLength());
for (String flag : cfg.getFlags()) {
cmd.appendArg(flag);
}
@@ -882,9 +950,9 @@
final Command cmd = new Command("network", "route", action, netId);
// create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
- final LinkAddress la = route.getDestination();
+ final LinkAddress la = route.getDestinationLinkAddress();
cmd.appendArg(route.getInterface());
- cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getNetworkPrefixLength());
+ cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getPrefixLength());
if (route.hasGateway()) {
cmd.appendArg(route.getGateway().getHostAddress());
}
@@ -1697,9 +1765,9 @@
public void setMarkedForwardingRoute(String iface, RouteInfo route) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- LinkAddress dest = route.getDestination();
+ LinkAddress dest = route.getDestinationLinkAddress();
mConnector.execute("interface", "fwmark", "route", "add", iface,
- dest.getAddress().getHostAddress(), dest.getNetworkPrefixLength());
+ dest.getAddress().getHostAddress(), dest.getPrefixLength());
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
@@ -1709,9 +1777,9 @@
public void clearMarkedForwardingRoute(String iface, RouteInfo route) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- LinkAddress dest = route.getDestination();
+ LinkAddress dest = route.getDestinationLinkAddress();
mConnector.execute("interface", "fwmark", "route", "remove", iface,
- dest.getAddress().getHostAddress(), dest.getNetworkPrefixLength());
+ dest.getAddress().getHostAddress(), dest.getPrefixLength());
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
@@ -1998,9 +2066,9 @@
final Command cmd = new Command("network", "route", "legacy", uid, action, netId);
// create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
- final LinkAddress la = routeInfo.getDestination();
+ final LinkAddress la = routeInfo.getDestinationLinkAddress();
cmd.appendArg(routeInfo.getInterface());
- cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getNetworkPrefixLength());
+ cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getPrefixLength());
if (routeInfo.hasGateway()) {
cmd.appendArg(routeInfo.getGateway().getHostAddress());
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index cfaf016..9d92421 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -33,10 +33,13 @@
import android.os.UserHandle;
import android.telephony.CellLocation;
import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.CellInfo;
+import android.telephony.VoLteServiceState;
import android.telephony.TelephonyManager;
import android.telephony.DisconnectCause;
import android.telephony.PreciseCallState;
@@ -65,8 +68,9 @@
*/
class TelephonyRegistry extends ITelephonyRegistry.Stub {
private static final String TAG = "TelephonyRegistry";
- private static final boolean DBG = false;
- private static final boolean DBG_LOC = false;
+ private static final boolean DBG = false; // STOPSHIP if true
+ private static final boolean DBG_LOC = false; // STOPSHIP if true
+ private static final boolean VDBG = false; // STOPSHIP if true
private static class Record {
String pkgForDebug;
@@ -79,6 +83,10 @@
int events;
+ long subId;
+
+ boolean isLegacyApp;
+
@Override
public String toString() {
return "{pkgForDebug=" + pkgForDebug + " callerUid=" + callerUid +
@@ -94,41 +102,47 @@
private final IBatteryStats mBatteryStats;
- private int mCallState = TelephonyManager.CALL_STATE_IDLE;
+ private int mNumPhones;
- private String mCallIncomingNumber = "";
+ private int[] mCallState;
- private ServiceState mServiceState = new ServiceState();
+ private String[] mCallIncomingNumber;
- private SignalStrength mSignalStrength = new SignalStrength();
+ private ServiceState[] mServiceState;
- private boolean mMessageWaiting = false;
+ private SignalStrength[] mSignalStrength;
- private boolean mCallForwarding = false;
+ private boolean[] mMessageWaiting;
- private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
+ private boolean[] mCallForwarding;
- private int mDataConnectionState = TelephonyManager.DATA_UNKNOWN;
+ private int[] mDataActivity;
- private boolean mDataConnectionPossible = false;
+ private int[] mDataConnectionState;
- private String mDataConnectionReason = "";
+ private boolean[] mDataConnectionPossible;
- private String mDataConnectionApn = "";
+ private String[] mDataConnectionReason;
+
+ private String[] mDataConnectionApn;
private ArrayList<String> mConnectedApns;
- private LinkProperties mDataConnectionLinkProperties;
+ private LinkProperties[] mDataConnectionLinkProperties;
- private NetworkCapabilities mDataConnectionNetworkCapabilities;
+ private NetworkCapabilities[] mDataConnectionNetworkCapabilities;
- private Bundle mCellLocation = new Bundle();
+ private Bundle[] mCellLocation;
- private int mDataConnectionNetworkType;
+ private int[] mDataConnectionNetworkType;
private int mOtaspMode = ServiceStateTracker.OTASP_UNKNOWN;
- private List<CellInfo> mCellInfo = null;
+ private ArrayList<List<CellInfo>> mCellInfo = null;
+
+ private VoLteServiceState mVoLteServiceState = new VoLteServiceState();
+
+ private long mDefaultSubId;
private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo();
@@ -148,21 +162,40 @@
PhoneStateListener.LISTEN_CALL_STATE |
PhoneStateListener.LISTEN_DATA_ACTIVITY |
PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
- PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
+ PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |
+ PhoneStateListener.LISTEN_VOLTE_STATE;;
static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE;
private static final int MSG_USER_SWITCHED = 1;
+ private static final int MSG_UPDATE_DEFAULT_SUB = 2;
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_USER_SWITCHED: {
- if (DBG) Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
- TelephonyRegistry.this.notifyCellLocation(mCellLocation);
+ Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
+ int numPhones = TelephonyManager.getDefault().getPhoneCount();
+ for (int sub = 0; sub < numPhones; sub++) {
+ TelephonyRegistry.this.notifyCellLocationUsingSubId(sub, mCellLocation[sub]);
+ }
+ break;
+ }
+ case MSG_UPDATE_DEFAULT_SUB: {
+ Slog.d(TAG, "MSG_UPDATE_DEFAULT_SUB subid=" + mDefaultSubId);
+ // Default subscription id changed, update the changed default subscription
+ // id in all the legacy application listener records.
+ synchronized (mRecords) {
+ for (Record r : mRecords) {
+ // FIXME: Be sure we're using isLegacyApp correctly!
+ if (r.isLegacyApp == true) {
+ r.subId = mDefaultSubId;
+ }
+ }
+ }
break;
}
}
@@ -173,9 +206,14 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
+ Slog.d(TAG, "mBroadcastReceiver: action=" + action);
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED,
intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
+ } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) {
+ mDefaultSubId = intent.getLongExtra(PhoneConstants.SUBSCRIPTION_KEY,
+ SubscriptionManager.getDefaultSubId());
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_DEFAULT_SUB, 0, 0));
}
}
};
@@ -190,13 +228,55 @@
TelephonyRegistry(Context context) {
CellLocation location = CellLocation.getEmpty();
+ mContext = context;
+ mBatteryStats = BatteryStatsService.getService();
+ mConnectedApns = new ArrayList<String>();
+
+ // Initialize default subscription to be used for single standby.
+ mDefaultSubId = SubscriptionManager.getDefaultSubId();
+
+ int numPhones = TelephonyManager.getDefault().getPhoneCount();
+ if (DBG) Slog.d(TAG, "TelephonyRegistor: ctor numPhones=" + numPhones);
+ mNumPhones = numPhones;
+ mCallState = new int[numPhones];
+ mDataActivity = new int[numPhones];
+ mDataConnectionState = new int[numPhones];
+ mDataConnectionNetworkType = new int[numPhones];
+ mCallIncomingNumber = new String[numPhones];
+ mServiceState = new ServiceState[numPhones];
+ mSignalStrength = new SignalStrength[numPhones];
+ mMessageWaiting = new boolean[numPhones];
+ mDataConnectionPossible = new boolean[numPhones];
+ mDataConnectionReason = new String[numPhones];
+ mDataConnectionApn = new String[numPhones];
+ mCallForwarding = new boolean[numPhones];
+ mCellLocation = new Bundle[numPhones];
+ mDataConnectionLinkProperties = new LinkProperties[numPhones];
+ mDataConnectionNetworkCapabilities = new NetworkCapabilities[numPhones];
+ mCellInfo = new ArrayList<List<CellInfo>>();
+ for (int i = 0; i < numPhones; i++) {
+ mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
+ mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
+ mDataConnectionState[i] = TelephonyManager.DATA_UNKNOWN;
+ mCallIncomingNumber[i] = "";
+ mServiceState[i] = new ServiceState();
+ mSignalStrength[i] = new SignalStrength();
+ mMessageWaiting[i] = false;
+ mCallForwarding[i] = false;
+ mDataConnectionPossible[i] = false;
+ mDataConnectionReason[i] = "";
+ mDataConnectionApn[i] = "";
+ mCellLocation[i] = new Bundle();
+ mCellInfo.add(i, null);
+ }
+
// Note that location can be null for non-phone builds like
// like the generic one.
if (location != null) {
- location.fillInNotifierBundle(mCellLocation);
+ for (int i = 0; i < numPhones; i++) {
+ location.fillInNotifierBundle(mCellLocation[i]);
+ }
}
- mContext = context;
- mBatteryStats = BatteryStatsService.getService();
mConnectedApns = new ArrayList<String>();
}
@@ -205,16 +285,31 @@
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_REMOVED);
+ filter.addAction(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
+ Slog.d(TAG, "systemRunning register for intents");
mContext.registerReceiver(mBroadcastReceiver, filter);
}
@Override
public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
boolean notifyNow) {
+ listen(pkgForDebug, callback, events, notifyNow, mDefaultSubId, true);
+ }
+
+ @Override
+ public void listenUsingSubId(long subId, String pkgForDebug, IPhoneStateListener callback,
+ int events, boolean notifyNow) {
+ listen(pkgForDebug, callback, events, notifyNow, subId, false);
+ }
+
+ private void listen(String pkgForDebug, IPhoneStateListener callback, int events,
+ boolean notifyNow, long subId, boolean isLegacyApp) {
int callerUid = UserHandle.getCallingUserId();
int myUid = UserHandle.myUserId();
- if (DBG) {
+ if (VDBG) {
Slog.d(TAG, "listen: E pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events)
+ + " notifyNow=" + notifyNow + " subId=" + subId
+ + " isLegacyApp=" + isLegacyApp
+ " myUid=" + myUid
+ " callerUid=" + callerUid);
}
@@ -239,22 +334,37 @@
r.callback = callback;
r.pkgForDebug = pkgForDebug;
r.callerUid = callerUid;
+ r.subId = subId;
+ r.isLegacyApp = isLegacyApp;
+ // Legacy applications pass invalid subId(-1), based on
+ // the received subId value update the isLegacyApp field
+ if ((r.subId <= 0) || (r.subId == SubscriptionManager.INVALID_SUB_ID)) {
+ r.subId = mDefaultSubId;
+ r.isLegacyApp = true; // FIXME: is this needed ??
+ }
+ if (r.subId == SubscriptionManager.DEFAULT_SUB_ID) {
+ r.subId = mDefaultSubId;
+ if (DBG) Slog.i(TAG, "listen: DEFAULT_SUB_ID");
+ }
mRecords.add(r);
if (DBG) Slog.i(TAG, "listen: add new record=" + r);
}
+ int phoneId = SubscriptionManager.getPhoneId(subId);
int send = events & (events ^ r.events);
r.events = events;
- if (notifyNow) {
+ if (notifyNow && validatePhoneId(phoneId)) {
if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
try {
- r.callback.onServiceStateChanged(new ServiceState(mServiceState));
+ r.callback.onServiceStateChanged(
+ new ServiceState(mServiceState[phoneId]));
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
try {
- int gsmSignalStrength = mSignalStrength.getGsmSignalStrength();
+ int gsmSignalStrength = mSignalStrength[phoneId]
+ .getGsmSignalStrength();
r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
: gsmSignalStrength));
} catch (RemoteException ex) {
@@ -263,51 +373,56 @@
}
if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
try {
- r.callback.onMessageWaitingIndicatorChanged(mMessageWaiting);
+ r.callback.onMessageWaitingIndicatorChanged(
+ mMessageWaiting[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
try {
- r.callback.onCallForwardingIndicatorChanged(mCallForwarding);
+ r.callback.onCallForwardingIndicatorChanged(
+ mCallForwarding[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
try {
- if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation=" + mCellLocation);
- r.callback.onCellLocationChanged(new Bundle(mCellLocation));
+ if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation = "
+ + mCellLocation[phoneId]);
+ r.callback.onCellLocationChanged(
+ new Bundle(mCellLocation[phoneId]));
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
try {
- r.callback.onCallStateChanged(mCallState, mCallIncomingNumber);
+ r.callback.onCallStateChanged(mCallState[phoneId],
+ mCallIncomingNumber[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
try {
- r.callback.onDataConnectionStateChanged(mDataConnectionState,
- mDataConnectionNetworkType);
+ r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+ mDataConnectionNetworkType[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
try {
- r.callback.onDataActivity(mDataActivity);
+ r.callback.onDataActivity(mDataActivity[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
try {
- r.callback.onSignalStrengthsChanged(mSignalStrength);
+ r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -321,8 +436,9 @@
}
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
try {
- if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo=" + mCellInfo);
- r.callback.onCellInfoChanged(mCellInfo);
+ if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo[" + phoneId + "] = "
+ + mCellInfo.get(phoneId));
+ r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -373,10 +489,10 @@
return;
}
synchronized (mRecords) {
- mCallState = state;
- mCallIncomingNumber = incomingNumber;
for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
+ if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
+ (r.isLegacyApp == true)) {
+ // FIXME: why does isLegacyApp need to be true?
try {
r.callback.onCallStateChanged(state, incomingNumber);
} catch (RemoteException ex) {
@@ -386,82 +502,148 @@
}
handleRemoveListLocked();
}
- broadcastCallStateChanged(state, incomingNumber);
+ broadcastCallStateChanged(state, incomingNumber, mDefaultSubId);
}
- public void notifyServiceState(ServiceState state) {
+ public void notifyCallStateUsingSubId(long subId, int state, String incomingNumber) {
+ if (!checkNotifyPermission("notifyCallState()")) {
+ return;
+ }
+ if (VDBG) {
+ Slog.d(TAG, "notifyCallStateUsingSubId: subId=" + subId
+ + " state=" + state + " incomingNumber=" + incomingNumber);
+ }
+ synchronized (mRecords) {
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mCallState[phoneId] = state;
+ mCallIncomingNumber[phoneId] = incomingNumber;
+ for (Record r : mRecords) {
+ if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
+ (r.subId == subId) && (r.isLegacyApp == false)) {
+ // FIXME: why isLegacyApp false?
+ try {
+ r.callback.onCallStateChanged(state, incomingNumber);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ broadcastCallStateChanged(state, incomingNumber, subId);
+ }
+
+ public void notifyServiceState(ServiceState state) {
+ notifyServiceStateUsingSubId(mDefaultSubId, state);
+ }
+
+ public void notifyServiceStateUsingSubId(long subId, ServiceState state) {
if (!checkNotifyPermission("notifyServiceState()")){
return;
}
- long ident = Binder.clearCallingIdentity();
- try {
- mBatteryStats.notePhoneState(state.getState());
- } catch (RemoteException re) {
- // Can't do much
- } finally {
- Binder.restoreCallingIdentity(ident);
+ if (subId == SubscriptionManager.DEFAULT_SUB_ID) {
+ subId = mDefaultSubId;
+ Slog.d(TAG, "notifyServiceStateUsingSubId: using mDefaultSubId=" + mDefaultSubId);
+ }
+ if (VDBG) {
+ Slog.d(TAG, "notifyServiceStateUsingSubId: subId=" + subId
+ + " state=" + state);
}
synchronized (mRecords) {
- mServiceState = state;
- for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
- try {
- r.callback.onServiceStateChanged(new ServiceState(state));
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mServiceState[phoneId] = state;
+ for (Record r : mRecords) {
+ // FIXME: use DEFAULT_SUB_ID instead??
+ if (((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) &&
+ (r.subId == subId)) {
+ try {
+ r.callback.onServiceStateChanged(new ServiceState(state));
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
}
+ } else {
+ Slog.d(TAG, "notifyServiceStateUsingSubId: INVALID phoneId=" + phoneId);
}
handleRemoveListLocked();
}
- broadcastServiceStateChanged(state);
+ broadcastServiceStateChanged(state, subId);
}
public void notifySignalStrength(SignalStrength signalStrength) {
+ notifySignalStrengthUsingSubId(mDefaultSubId, signalStrength);
+ }
+
+ public void notifySignalStrengthUsingSubId(long subId, SignalStrength signalStrength) {
if (!checkNotifyPermission("notifySignalStrength()")) {
return;
}
+ if (VDBG) {
+ Slog.d(TAG, "notifySignalStrengthUsingSubId: subId=" + subId
+ + " signalStrength=" + signalStrength);
+ }
synchronized (mRecords) {
- mSignalStrength = signalStrength;
- for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
- try {
- r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mSignalStrength[phoneId] = signalStrength;
+ for (Record r : mRecords) {
+ if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) &&
+ (r.subId == subId)){
+ try {
+ r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
- }
- if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
- try {
- int gsmSignalStrength = signalStrength.getGsmSignalStrength();
- r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
- : gsmSignalStrength));
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
+ if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) &&
+ (r.subId == subId)) {
+ try {
+ int gsmSignalStrength = signalStrength.getGsmSignalStrength();
+ r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
+ : gsmSignalStrength));
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
}
}
handleRemoveListLocked();
}
- broadcastSignalStrengthChanged(signalStrength);
+ broadcastSignalStrengthChanged(signalStrength, subId);
}
public void notifyCellInfo(List<CellInfo> cellInfo) {
+ notifyCellInfoUsingSubId(mDefaultSubId, cellInfo);
+ }
+
+ public void notifyCellInfoUsingSubId(long subId, List<CellInfo> cellInfo) {
if (!checkNotifyPermission("notifyCellInfo()")) {
return;
}
+ if (VDBG) {
+ Slog.d(TAG, "notifyCellInfoUsingSubId: subId=" + subId
+ + " cellInfo=" + cellInfo);
+ }
synchronized (mRecords) {
- mCellInfo = cellInfo;
- for (Record r : mRecords) {
- if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
- try {
- if (DBG_LOC) {
- Slog.d(TAG, "notifyCellInfo: mCellInfo=" + mCellInfo + " r=" + r);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mCellInfo.set(phoneId, cellInfo);
+ for (Record r : mRecords) {
+ if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)
+ && r.subId == subId) {
+ try {
+ if (DBG_LOC) {
+ Slog.d(TAG, "notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
+ }
+ r.callback.onCellInfoChanged(cellInfo);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
}
- r.callback.onCellInfoChanged(cellInfo);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
}
}
}
@@ -495,17 +677,29 @@
}
public void notifyMessageWaitingChanged(boolean mwi) {
+ notifyMessageWaitingChangedUsingSubId(mDefaultSubId, mwi);
+ }
+
+ public void notifyMessageWaitingChangedUsingSubId(long subId, boolean mwi) {
if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
return;
}
+ if (VDBG) {
+ Slog.d(TAG, "notifyMessageWaitingChangedUsingSubId: subId=" + subId
+ + " mwi=" + mwi);
+ }
synchronized (mRecords) {
- mMessageWaiting = mwi;
- for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
- try {
- r.callback.onMessageWaitingIndicatorChanged(mwi);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mMessageWaiting[phoneId] = mwi;
+ for (Record r : mRecords) {
+ if (((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) &&
+ (r.subId == subId)) {
+ try {
+ r.callback.onMessageWaitingIndicatorChanged(mwi);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
}
}
@@ -514,17 +708,29 @@
}
public void notifyCallForwardingChanged(boolean cfi) {
+ notifyCallForwardingChangedUsingSubId(mDefaultSubId, cfi);
+ }
+
+ public void notifyCallForwardingChangedUsingSubId(long subId, boolean cfi) {
if (!checkNotifyPermission("notifyCallForwardingChanged()")) {
return;
}
+ if (VDBG) {
+ Slog.d(TAG, "notifyCallForwardingChangedUsingSubId: subId=" + subId
+ + " cfi=" + cfi);
+ }
synchronized (mRecords) {
- mCallForwarding = cfi;
- for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
- try {
- r.callback.onCallForwardingIndicatorChanged(cfi);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mCallForwarding[phoneId] = cfi;
+ for (Record r : mRecords) {
+ if (((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) &&
+ (r.subId == subId)) {
+ try {
+ r.callback.onCallForwardingIndicatorChanged(cfi);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
}
}
@@ -533,11 +739,16 @@
}
public void notifyDataActivity(int state) {
+ notifyDataActivityUsingSubId(mDefaultSubId, state);
+ }
+
+ public void notifyDataActivityUsingSubId(long subId, int state) {
if (!checkNotifyPermission("notifyDataActivity()" )) {
return;
}
synchronized (mRecords) {
- mDataActivity = state;
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ mDataActivity[phoneId] = state;
for (Record r : mRecords) {
if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
try {
@@ -554,29 +765,40 @@
public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
String reason, String apn, String apnType, LinkProperties linkProperties,
NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
+ notifyDataConnectionUsingSubId(mDefaultSubId, state, isDataConnectivityPossible,
+ reason, apn, apnType, linkProperties,
+ networkCapabilities, networkType, roaming);
+ }
+
+ public void notifyDataConnectionUsingSubId(long subId, int state,
+ boolean isDataConnectivityPossible, String reason, String apn, String apnType,
+ LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
+ int networkType, boolean roaming) {
if (!checkNotifyPermission("notifyDataConnection()" )) {
return;
}
- if (DBG) {
- Slog.i(TAG, "notifyDataConnection: state=" + state + " isDataConnectivityPossible="
- + isDataConnectivityPossible + " reason='" + reason
+ if (VDBG) {
+ Slog.i(TAG, "notifyDataConnectionUsingSubId: subId=" + subId
+ + " state=" + state + " isDataConnectivityPossible=" + isDataConnectivityPossible
+ + " reason='" + reason
+ "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType
+ " mRecords.size()=" + mRecords.size() + " mRecords=" + mRecords);
}
synchronized (mRecords) {
+ int phoneId = SubscriptionManager.getPhoneId(subId);
boolean modified = false;
if (state == TelephonyManager.DATA_CONNECTED) {
if (!mConnectedApns.contains(apnType)) {
mConnectedApns.add(apnType);
- if (mDataConnectionState != state) {
- mDataConnectionState = state;
+ if (mDataConnectionState[phoneId] != state) {
+ mDataConnectionState[phoneId] = state;
modified = true;
}
}
} else {
if (mConnectedApns.remove(apnType)) {
if (mConnectedApns.isEmpty()) {
- mDataConnectionState = state;
+ mDataConnectionState[phoneId] = state;
modified = true;
} else {
// leave mDataConnectionState as is and
@@ -584,25 +806,28 @@
}
}
}
- mDataConnectionPossible = isDataConnectivityPossible;
- mDataConnectionReason = reason;
- mDataConnectionLinkProperties = linkProperties;
- mDataConnectionNetworkCapabilities = networkCapabilities;
- if (mDataConnectionNetworkType != networkType) {
- mDataConnectionNetworkType = networkType;
+ mDataConnectionPossible[phoneId] = isDataConnectivityPossible;
+ mDataConnectionReason[phoneId] = reason;
+ mDataConnectionLinkProperties[phoneId] = linkProperties;
+ mDataConnectionNetworkCapabilities[phoneId] = networkCapabilities;
+ if (mDataConnectionNetworkType[phoneId] != networkType) {
+ mDataConnectionNetworkType[phoneId] = networkType;
// need to tell registered listeners about the new network type
modified = true;
}
if (modified) {
if (DBG) {
- Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState
- + ", " + mDataConnectionNetworkType + ")");
+ Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
+ + ", " + mDataConnectionNetworkType[phoneId] + ")");
}
for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
+ if (((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) &&
+ (r.subId == subId)) {
try {
- r.callback.onDataConnectionStateChanged(mDataConnectionState,
- mDataConnectionNetworkType);
+ Slog.d(TAG,"Notify data connection state changed on sub: " +
+ subId);
+ r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+ mDataConnectionNetworkType[phoneId]);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -624,15 +849,24 @@
handleRemoveListLocked();
}
broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
- apnType, linkProperties, networkCapabilities, roaming);
+ apnType, linkProperties, networkCapabilities, roaming, subId);
broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
linkProperties, "");
}
public void notifyDataConnectionFailed(String reason, String apnType) {
+ notifyDataConnectionFailedUsingSubId(mDefaultSubId, reason, apnType);
+ }
+
+ public void notifyDataConnectionFailedUsingSubId(long subId,
+ String reason, String apnType) {
if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
return;
}
+ if (VDBG) {
+ Slog.d(TAG, "notifyDataConnectionFailedUsingSubId: subId=" + subId
+ + " reason=" + reason + " apnType=" + apnType);
+ }
synchronized (mRecords) {
mPreciseDataConnectionState = new PreciseDataConnectionState(
TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN,
@@ -648,29 +882,42 @@
}
handleRemoveListLocked();
}
- broadcastDataConnectionFailed(reason, apnType);
+ broadcastDataConnectionFailed(reason, apnType, subId);
broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", reason, null, "");
}
public void notifyCellLocation(Bundle cellLocation) {
+ notifyCellLocationUsingSubId(mDefaultSubId, cellLocation);
+ }
+
+ public void notifyCellLocationUsingSubId(long subId, Bundle cellLocation) {
+ Slog.d(TAG, "notifyCellLocationUsingSubId: subId=" + subId
+ + " cellLocation=" + cellLocation);
if (!checkNotifyPermission("notifyCellLocation()")) {
return;
}
+ if (VDBG) {
+ Slog.d(TAG, "notifyCellLocationUsingSubId: subId=" + subId
+ + " cellLocation=" + cellLocation);
+ }
synchronized (mRecords) {
- mCellLocation = cellLocation;
- for (Record r : mRecords) {
- if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
- try {
- if (DBG_LOC) {
- Slog.d(TAG, "notifyCellLocation: mCellLocation=" + mCellLocation
- + " r=" + r);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mCellLocation[phoneId] = cellLocation;
+ for (Record r : mRecords) {
+ if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)
+ && r.subId == subId) {
+ try {
+ if (DBG_LOC) {
+ Slog.d(TAG, "notifyCellLocation: cellLocation=" + cellLocation
+ + " r=" + r);
+ }
+ r.callback.onCellLocationChanged(new Bundle(cellLocation));
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
}
- r.callback.onCellLocationChanged(new Bundle(cellLocation));
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
}
-
}
}
handleRemoveListLocked();
@@ -771,6 +1018,26 @@
TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, reason, null, failCause);
}
+ public void notifyVoLteServiceStateChanged(VoLteServiceState lteState) {
+ if (!checkNotifyPermission("notifyVoLteServiceStateChanged()")) {
+ return;
+ }
+ synchronized (mRecords) {
+ mVoLteServiceState = lteState;
+ for (Record r : mRecords) {
+ if ((r.events & PhoneStateListener.LISTEN_VOLTE_STATE) != 0) {
+ try {
+ r.callback.onVoLteServiceStateChanged(
+ new VoLteServiceState(mVoLteServiceState));
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -810,15 +1077,26 @@
// the legacy intent broadcasting
//
- private void broadcastServiceStateChanged(ServiceState state) {
+ private void broadcastServiceStateChanged(ServiceState state, long subId) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.notePhoneState(state.getState());
+ } catch (RemoteException re) {
+ // Can't do much
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
Bundle data = new Bundle();
state.fillInNotifierBundle(data);
intent.putExtras(data);
+ // Pass the subscription along with the intent.
+ intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private void broadcastSignalStrengthChanged(SignalStrength signalStrength) {
+ private void broadcastSignalStrengthChanged(SignalStrength signalStrength, long subId) {
long ident = Binder.clearCallingIdentity();
try {
mBatteryStats.notePhoneSignalStrength(signalStrength);
@@ -833,10 +1111,11 @@
Bundle data = new Bundle();
signalStrength.fillInNotifierBundle(data);
intent.putExtras(data);
+ intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private void broadcastCallStateChanged(int state, String incomingNumber) {
+ private void broadcastCallStateChanged(int state, String incomingNumber, long subId) {
long ident = Binder.clearCallingIdentity();
try {
if (state == TelephonyManager.CALL_STATE_IDLE) {
@@ -856,6 +1135,7 @@
if (!TextUtils.isEmpty(incomingNumber)) {
intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
}
+ intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
android.Manifest.permission.READ_PHONE_STATE);
}
@@ -863,7 +1143,7 @@
private void broadcastDataConnectionStateChanged(int state,
boolean isDataConnectivityPossible,
String reason, String apn, String apnType, LinkProperties linkProperties,
- NetworkCapabilities networkCapabilities, boolean roaming) {
+ NetworkCapabilities networkCapabilities, boolean roaming, long subId) {
// Note: not reporting to the battery stats service here, because the
// status bar takes care of that after taking into account all of the
// required info.
@@ -890,13 +1170,16 @@
intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
+ intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private void broadcastDataConnectionFailed(String reason, String apnType) {
+ private void broadcastDataConnectionFailed(String reason, String apnType,
+ long subId) {
Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
intent.putExtra(PhoneConstants.FAILURE_REASON_KEY, reason);
intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
+ intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -989,4 +1272,10 @@
}
return valid;
}
+
+ private boolean validatePhoneId(int phoneId) {
+ boolean valid = (phoneId >= 0) && (phoneId < mNumPhones);
+ if (VDBG) Slog.d(TAG, "validatePhoneId: " + valid);
+ return valid;
+ }
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index b2aaf74..e152ebe 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -537,13 +537,16 @@
}
@Override
- public AuthenticatorDescription[] getAuthenticatorTypes() {
+ public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getAuthenticatorTypes: "
+ + "for user id " + userId
+ "caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
- final int userId = UserHandle.getCallingUserId();
+ // Only allow the system process to read accounts of other users
+ enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
+ + " trying get authenticator types for " + userId);
final long identityToken = clearCallingIdentity();
try {
Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
@@ -562,6 +565,16 @@
}
}
+ private void enforceCrossUserPermission(int userId, String errorMessage) {
+ if (userId != UserHandle.getCallingUserId()
+ && Binder.getCallingUid() != Process.myUid()
+ && mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(errorMessage);
+ }
+ }
+
@Override
public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -1567,14 +1580,8 @@
final Account account, final Bundle options, final boolean expectActivityLaunch,
int userId) {
// Only allow the system process to read accounts of other users
- if (userId != UserHandle.getCallingUserId()
- && Binder.getCallingUid() != Process.myUid()
- && mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("User " + UserHandle.getCallingUserId()
+ enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
+ " trying to confirm account credentials for " + userId);
- }
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "confirmCredentials: " + account
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fa26d56..697e1f2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -270,7 +270,7 @@
static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
// Maximum number of recent tasks that we can remember.
- static final int MAX_RECENT_TASKS = ActivityManager.isLowRamDeviceStatic() ? 10 : 20;
+ static final int MAX_RECENT_TASKS = ActivityManager.isLowRamDeviceStatic() ? 10 : 200;
// Amount of time after a call to stopAppSwitches() during which we will
// prevent further untrusted switches from happening.
@@ -3538,6 +3538,9 @@
// Remove any existing entries that are the same kind of task.
final Intent intent = task.intent;
final boolean document = intent != null && intent.isDocument();
+ final ComponentName comp = intent.getComponent();
+
+ int maxRecents = task.maxRecents - 1;
for (int i=0; i<N; i++) {
TaskRecord tr = mRecentTasks.get(i);
if (task != tr) {
@@ -3549,14 +3552,24 @@
(intent == null || !intent.filterEquals(trIntent))) {
continue;
}
- if (document || trIntent != null && trIntent.isDocument()) {
- // Document tasks do not match other tasks.
+ final boolean trIsDocument = trIntent != null && trIntent.isDocument();
+ if (document && trIsDocument) {
+ // These are the same document activity (not necessarily the same doc).
+ if (maxRecents > 0) {
+ --maxRecents;
+ continue;
+ }
+ // Hit the maximum number of documents for this task. Fall through
+ // and remove this document from recents.
+ } else if (document || trIsDocument) {
+ // Only one of these is a document. Not the droid we're looking for.
continue;
}
}
// Either task and tr are the same or, their affinities match or their intents match
- // and neither of them is a document.
+ // and neither of them is a document, or they are documents using the same activity
+ // and their maxRecents has been reached.
tr.disposeThumbnail();
mRecentTasks.remove(i);
i--;
@@ -3566,6 +3579,7 @@
// specified, then replace it with the existing recent task.
task = tr;
}
+ mTaskPersister.notify(tr, false);
}
if (N >= MAX_RECENT_TASKS) {
mRecentTasks.remove(N-1).disposeThumbnail();
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 32722bc..11f855e 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -906,6 +906,9 @@
}
startTime = 0;
finishLaunchTickingLocked();
+ if (task != null) {
+ task.hasBeenVisible = true;
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index e6b465d..03ce530 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -32,12 +32,12 @@
import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_APP;
+import static com.android.server.am.ActivityStackSupervisor.DEBUG_CONTAINERS;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_SCREENSHOTS;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-import android.service.voice.IVoiceInteractionSession;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.Watchdog;
@@ -74,6 +74,7 @@
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
import android.util.EventLog;
import android.util.Slog;
import android.view.Display;
@@ -549,14 +550,16 @@
if (DEBUG_TASKS) Slog.d(TAG, "Found matching affinity!");
return r;
}
- } else if (taskIntent != null && taskIntent.getComponent().equals(cls) &&
+ } else if (taskIntent != null && taskIntent.getComponent() != null &&
+ taskIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");
//dump();
if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: "
+ r.intent);
return r;
- } else if (affinityIntent != null && affinityIntent.getComponent().equals(cls) &&
+ } else if (affinityIntent != null && affinityIntent.getComponent() != null &&
+ affinityIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");
//dump();
@@ -1403,7 +1406,7 @@
ActivityRecord parent = mActivityContainer.mParentActivity;
if ((parent != null && parent.state != ActivityState.RESUMED) ||
- !mActivityContainer.isAttached()) {
+ !mActivityContainer.isAttachedLocked()) {
// Do not resume this stack if its parent is not resumed.
// TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
return false;
@@ -2675,11 +2678,14 @@
|| prevState == ActivityState.INITIALIZING) {
// If this activity is already stopped, we can just finish
// it right now.
- boolean activityRemoved = destroyActivityLocked(r, true,
- oomAdj, "finish-imm");
+ r.makeFinishing();
+ boolean activityRemoved = destroyActivityLocked(r, true, oomAdj, "finish-imm");
if (activityRemoved) {
mStackSupervisor.resumeTopActivitiesLocked();
}
+ if (DEBUG_CONTAINERS) Slog.d(TAG,
+ "destroyActivityLocked: finishCurrentActivityLocked r=" + r +
+ " destroy returned removed=" + activityRemoved);
return activityRemoved ? null : r;
}
@@ -3042,6 +3048,7 @@
if (r != null) {
mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
}
+ if (DEBUG_CONTAINERS) Slog.d(TAG, "activityDestroyedLocked: r=" + r);
if (isInStackLocked(token) != null) {
if (r.state == ActivityState.DESTROYING) {
@@ -3801,7 +3808,7 @@
mStacks.remove(this);
mStacks.add(0, this);
}
- mActivityContainer.onTaskListEmpty();
+ mActivityContainer.onTaskListEmptyLocked();
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 35ac9c9..66e9eb3e 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -107,10 +107,11 @@
static final boolean DEBUG = ActivityManagerService.DEBUG || false;
static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
static final boolean DEBUG_APP = DEBUG || false;
- static final boolean DEBUG_SAVED_STATE = DEBUG || false;
- static final boolean DEBUG_STATES = DEBUG || false;
+ static final boolean DEBUG_CONTAINERS = DEBUG || false;
static final boolean DEBUG_IDLE = DEBUG || false;
+ static final boolean DEBUG_SAVED_STATE = DEBUG || false;
static final boolean DEBUG_SCREENSHOTS = DEBUG || false;
+ static final boolean DEBUG_STATES = DEBUG || false;
public static final int HOME_STACK_ID = 0;
@@ -135,6 +136,7 @@
static final int LOCK_TASK_START_MSG = FIRST_SUPERVISOR_STACK_MSG + 9;
static final int LOCK_TASK_END_MSG = FIRST_SUPERVISOR_STACK_MSG + 10;
static final int CONTAINER_CALLBACK_TASK_LIST_EMPTY = FIRST_SUPERVISOR_STACK_MSG + 11;
+ static final int CONTAINER_TASK_LIST_EMPTY_TIMEOUT = FIRST_SUPERVISOR_STACK_MSG + 12;
private final static String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay";
@@ -239,7 +241,7 @@
// TODO: Add listener for removal of references.
/** Mapping from (ActivityStack/TaskStack).mStackId to their current state */
- SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>();
+ private SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>();
/** Mapping from displayId to display current state */
private final SparseArray<ActivityDisplay> mActivityDisplays =
@@ -1269,7 +1271,7 @@
// to ensure that it is safe to do so. If the upcoming activity will also
// be part of the voice session, we can only launch it if it has explicitly
// said it supports the VOICE category, or it is a part of the calling app.
- if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
+ if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
&& sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
try {
if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(),
@@ -1486,6 +1488,47 @@
int launchFlags = intent.getFlags();
+ if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
+ (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ||
+ r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK)) {
+ // We have a conflict between the Intent and the Activity manifest, manifest wins.
+ Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
+ "\"singleInstance\" or \"singleTask\"");
+ launchFlags &=
+ ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ } else {
+ switch (r.info.documentLaunchMode) {
+ case ActivityInfo.DOCUMENT_LAUNCH_NONE:
+ break;
+ case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
+ launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+ break;
+ case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
+ launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+ break;
+ case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
+ launchFlags &= ~Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+ break;
+ }
+ }
+
+ if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+ // For whatever reason this activity is being launched into a new
+ // task... yet the caller has requested a result back. Well, that
+ // is pretty messed up, so instead immediately send back a cancel
+ // and let the new task continue launched as normal without a
+ // dependency on its originator.
+ Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
+ r.resultTo.task.stack.sendActivityResultLocked(-1,
+ r.resultTo, r.resultWho, r.requestCode,
+ Activity.RESULT_CANCELED, null);
+ r.resultTo = null;
+ }
+
+ if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
+ launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
+ }
+
// We'll invoke onUserLeaving before onPause only if the launching
// activity did not explicitly state that this is an automated launch.
mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
@@ -1516,20 +1559,6 @@
}
}
- switch (r.info.documentLaunchMode) {
- case ActivityInfo.DOCUMENT_LAUNCH_NONE:
- break;
- case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
- intent.addFlags(
- Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- launchFlags = intent.getFlags();
- break;
- case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
- launchFlags = intent.getFlags();
- break;
- }
- final boolean newDocument = intent.isDocument();
if (sourceRecord == null) {
// This activity is not being started from another... in this
// case we -always- start a new task.
@@ -1538,11 +1567,6 @@
"Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
- } else if (newDocument) {
- if (r.launchMode != ActivityInfo.LAUNCH_MULTIPLE) {
- Slog.w(TAG, "FLAG_ACTIVITY_NEW_DOCUMENT and launchMode != \"standard\"");
- r.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
- }
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// The original activity who is starting us is running as a single
// instance... this new activity it is starting must go on its
@@ -1581,18 +1605,7 @@
sourceStack = null;
}
- if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
- // For whatever reason this activity is being launched into a new
- // task... yet the caller has requested a result back. Well, that
- // is pretty messed up, so instead immediately send back a cancel
- // and let the new task continue launched as normal without a
- // dependency on its originator.
- Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
- r.resultTo.task.stack.sendActivityResultLocked(-1,
- r.resultTo, r.resultWho, r.requestCode,
- Activity.RESULT_CANCELED, null);
- r.resultTo = null;
- }
+ intent.setFlags(launchFlags);
boolean addingToTask = false;
boolean movedHome = false;
@@ -1827,7 +1840,7 @@
// Should this be considered a new task?
if (r.resultTo == null && !addingToTask
- && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+ && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
if (isLockTaskModeViolation(reuseTask)) {
Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
@@ -2244,8 +2257,10 @@
ActivityContainer createActivityContainer(ActivityRecord parentActivity,
IActivityContainerCallback callback) {
- ActivityContainer activityContainer = new VirtualActivityContainer(parentActivity, callback);
+ ActivityContainer activityContainer =
+ new VirtualActivityContainer(parentActivity, callback);
mActivityContainers.put(activityContainer.mStackId, activityContainer);
+ if (DEBUG_CONTAINERS) Slog.d(TAG, "createActivityContainer: " + activityContainer);
parentActivity.mChildContainers.add(activityContainer);
return activityContainer;
}
@@ -2254,6 +2269,8 @@
final ArrayList<ActivityContainer> childStacks = parentActivity.mChildContainers;
for (int containerNdx = childStacks.size() - 1; containerNdx >= 0; --containerNdx) {
ActivityContainer container = childStacks.remove(containerNdx);
+ if (DEBUG_CONTAINERS) Slog.d(TAG, "removeChildActivityContainers: removing " +
+ container);
container.release();
}
}
@@ -2261,11 +2278,8 @@
void deleteActivityContainer(IActivityContainer container) {
ActivityContainer activityContainer = (ActivityContainer)container;
if (activityContainer != null) {
- activityContainer.mStack.finishAllActivitiesLocked();
- final ActivityRecord parent = activityContainer.mParentActivity;
- if (parent != null) {
- parent.mChildContainers.remove(activityContainer);
- }
+ if (DEBUG_CONTAINERS) Slog.d(TAG, "deleteActivityContainer: ",
+ new RuntimeException("here").fillInStackTrace());
final int stackId = activityContainer.mStackId;
mActivityContainers.remove(stackId);
mWindowManager.removeStack(stackId);
@@ -2874,16 +2888,19 @@
@Override
public void onDisplayAdded(int displayId) {
+ Slog.v(TAG, "Display added displayId=" + displayId);
mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_ADDED, displayId, 0));
}
@Override
public void onDisplayRemoved(int displayId) {
+ Slog.v(TAG, "Display removed displayId=" + displayId);
mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_REMOVED, displayId, 0));
}
@Override
public void onDisplayChanged(int displayId) {
+ Slog.v(TAG, "Display changed displayId=" + displayId);
mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_CHANGED, displayId, 0));
}
@@ -3117,13 +3134,20 @@
}
}
} break;
+ case CONTAINER_TASK_LIST_EMPTY_TIMEOUT: {
+ synchronized (mService) {
+ Slog.w(TAG, "Timeout waiting for all activities in task to finish. " +
+ msg.obj);
+ ((ActivityContainer) msg.obj).onTaskListEmptyLocked();
+ }
+ } break;
}
}
}
class ActivityContainer extends android.app.IActivityContainer.Stub {
final static int FORCE_NEW_TASK_FLAGS = Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION;
final int mStackId;
IActivityContainerCallback mCallback = null;
final ActivityStack mStack;
@@ -3173,8 +3197,10 @@
@Override
public int getDisplayId() {
- if (mActivityDisplay != null) {
- return mActivityDisplay.mDisplayId;
+ synchronized (mService) {
+ if (mActivityDisplay != null) {
+ return mActivityDisplay.mDisplayId;
+ }
}
return -1;
}
@@ -3183,10 +3209,12 @@
public boolean injectEvent(InputEvent event) {
final long origId = Binder.clearCallingIdentity();
try {
- if (mActivityDisplay != null) {
- return mInputManagerInternal.injectInputEvent(event,
- mActivityDisplay.mDisplayId,
- InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ synchronized (mService) {
+ if (mActivityDisplay != null) {
+ return mInputManagerInternal.injectInputEvent(event,
+ mActivityDisplay.mDisplayId,
+ InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ }
}
return false;
} finally {
@@ -3196,10 +3224,23 @@
@Override
public void release() {
- mContainerState = CONTAINER_STATE_FINISHING;
- mStack.finishAllActivitiesLocked();
- detachLocked();
- mWindowManager.removeStack(mStackId);
+ synchronized (mService) {
+ if (mContainerState == CONTAINER_STATE_FINISHING) {
+ return;
+ }
+ mContainerState = CONTAINER_STATE_FINISHING;
+
+ final Message msg =
+ mHandler.obtainMessage(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
+ mHandler.sendMessageDelayed(msg, 1000);
+
+ long origId = Binder.clearCallingIdentity();
+ try {
+ mStack.finishAllActivitiesLocked();
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
}
private void detachLocked() {
@@ -3290,15 +3331,17 @@
return ActivityStackSupervisor.this;
}
- boolean isAttached() {
+ boolean isAttachedLocked() {
return mActivityDisplay != null;
}
void getBounds(Point outBounds) {
- if (mActivityDisplay != null) {
- mActivityDisplay.getBounds(outBounds);
- } else {
- outBounds.set(0, 0);
+ synchronized (mService) {
+ if (mActivityDisplay != null) {
+ mActivityDisplay.getBounds(outBounds);
+ } else {
+ outBounds.set(0, 0);
+ }
}
}
@@ -3321,7 +3364,12 @@
return true;
}
- void onTaskListEmpty() {
+ void onTaskListEmptyLocked() {
+ mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
+ if (!mStack.isHomeStack()) {
+ detachLocked();
+ deleteActivityContainer(this);
+ }
mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
}
@@ -3340,7 +3388,7 @@
mParentActivity = parent;
mCallback = callback;
mContainerState = CONTAINER_STATE_NO_SURFACE;
- mIdString = "VirtualActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}";
+ mIdString = "VirtualActivityContainer{" + mStackId + ", parent=" + mParentActivity + "}";
}
@Override
@@ -3386,22 +3434,22 @@
}
}
- setSurfaceIfReady();
+ setSurfaceIfReadyLocked();
if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display="
+ virtualActivityDisplay);
}
@Override
- boolean isAttached() {
- return mSurface != null && super.isAttached();
+ boolean isAttachedLocked() {
+ return mSurface != null && super.isAttachedLocked();
}
@Override
void setDrawn() {
synchronized (mService) {
mDrawn = true;
- setSurfaceIfReady();
+ setSurfaceIfReadyLocked();
}
}
@@ -3411,8 +3459,8 @@
return false;
}
- private void setSurfaceIfReady() {
- if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReady: mDrawn=" + mDrawn +
+ private void setSurfaceIfReadyLocked() {
+ if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
" mContainerState=" + mContainerState + " mSurface=" + mSurface);
if (mDrawn && mSurface != null && mContainerState == CONTAINER_STATE_NO_SURFACE) {
((VirtualActivityDisplay) mActivityDisplay).setSurface(mSurface);
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 3bfaca9..bb289fa 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -227,7 +227,7 @@
for (int fileNdx = 0; fileNdx < files.length; ++fileNdx) {
File file = files[fileNdx];
String filename = file.getName();
- final int taskIdEnd = filename.indexOf('_') + 1;
+ final int taskIdEnd = filename.indexOf('_');
if (taskIdEnd > 0) {
final int taskId;
try {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index ce83ae6..81a0b36 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -73,6 +73,7 @@
boolean rootWasReset; // True if the intent at the root of the task had
// the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
boolean askedCompatMode;// Have asked the user about compat mode for this task.
+ boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
String stringName; // caching of toString() result.
int userId; // user for which this task was created
@@ -96,6 +97,7 @@
/** Takes on same value as first root activity */
boolean isPersistable = false;
+ int maxRecents;
/** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
* determining the order when restoring. Sign indicates whether last task movement was to front
@@ -104,6 +106,7 @@
/** True if persistable, has changed, and has not yet been persisted */
boolean needsPersisting = false;
+
/** Launch the home activity when leaving this task. Will be false for tasks that are not on
* Display.DEFAULT_DISPLAY. */
boolean mOnTopOfHome = false;
@@ -301,6 +304,8 @@
if (mActivities.isEmpty()) {
taskType = r.mActivityType;
isPersistable = r.isPersistable();
+ // Clamp to [1, 100].
+ maxRecents = Math.min(Math.max(r.info.maxRecents, 1), 100);
} else {
// Otherwise make all added activities match this one.
r.mActivityType = taskType;
@@ -324,8 +329,12 @@
}
boolean autoRemoveFromRecents() {
- return intent != null &&
- (intent.getFlags() & Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS) != 0;
+ // We will automatically remove the task either if it has explicitly asked for
+ // this, or it is empty and has never contained an activity that got shown to
+ // the user.
+ return (intent != null &&
+ (intent.getFlags() & Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS) != 0) ||
+ (mActivities.isEmpty() && !hasBeenVisible);
}
/**
@@ -643,8 +652,9 @@
final int numActivities = activities.size();
for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
- if (!r.isPersistable() || (r.intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) ==
- Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) {
+ if (!r.isPersistable() || (activityNdx > 0 &&
+ (r.intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0)) {
+ // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
break;
}
out.startTag(null, TAG_ACTIVITY);
@@ -795,7 +805,8 @@
}
pw.print(prefix); pw.print("lastThumbnail="); pw.print(lastThumbnail);
pw.print(" lastDescription="); pw.println(lastDescription);
- pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime);
+ pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible);
+ pw.print(" lastActiveTime="); pw.print(lastActiveTime);
pw.print(" (inactive for ");
pw.print((getInactiveDuration()/1000)); pw.println("s)");
}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index c93f85d..ec3389b 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -1346,7 +1346,7 @@
if (iface != null) {
String[] dnsServers = mDefaultDnsServers;
- Collection<InetAddress> dnses = linkProperties.getDnses();
+ Collection<InetAddress> dnses = linkProperties.getDnsServers();
if (dnses != null) {
// we currently only handle IPv4
ArrayList<InetAddress> v4Dnses =
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 7f43e43..e80aecd 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -111,12 +111,15 @@
}
}
- static boolean shouldBlank(int state) {
- return state == Display.STATE_OFF;
- }
-
- static boolean shouldUnblank(int state) {
- return state == Display.STATE_ON || state == Display.STATE_DOZING;
+ static int getPowerModeForState(int state) {
+ switch (state) {
+ case Display.STATE_OFF:
+ return SurfaceControl.POWER_MODE_OFF;
+ case Display.STATE_DOZING:
+ return SurfaceControl.POWER_MODE_DOZE;
+ default:
+ return SurfaceControl.POWER_MODE_NORMAL;
+ }
}
private final class LocalDisplayDevice extends DisplayDevice {
@@ -204,11 +207,8 @@
@Override
public void requestDisplayStateLocked(int state) {
if (mState != state) {
- if (shouldBlank(state) && !shouldBlank(mState)) {
- SurfaceControl.blankDisplay(getDisplayTokenLocked());
- } else if (shouldUnblank(state) && !shouldUnblank(mState)) {
- SurfaceControl.unblankDisplay(getDisplayTokenLocked());
- }
+ SurfaceControl.setDisplayPowerMode(getDisplayTokenLocked(),
+ getPowerModeForState(state));
mState = state;
updateDeviceInfoLocked();
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
new file mode 100644
index 0000000..2941574
--- /dev/null
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -0,0 +1,328 @@
+/**
+ * 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.server.fingerprint;
+
+import android.app.Service;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.service.fingerprint.FingerprintManager;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+
+import android.service.fingerprint.FingerprintUtils;
+import android.service.fingerprint.IFingerprintService;
+import android.service.fingerprint.IFingerprintServiceReceiver;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * A service to manage multiple clients that want to access the fingerprint HAL API.
+ * The service is responsible for maintaining a list of clients and dispatching all
+ * fingerprint -related events.
+ *
+ * @hide
+ */
+public class FingerprintService extends SystemService {
+ private final String TAG = "FingerprintService";
+ private static final boolean DEBUG = true;
+ private ArrayMap<IBinder, ClientData> mClients = new ArrayMap<IBinder, ClientData>();
+
+ private static final int MSG_NOTIFY = 10;
+
+ 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);
+ break;
+
+ default:
+ Slog.w(TAG, "Unknown message:" + msg.what);
+ }
+ }
+ };
+ private Context mContext;
+
+ private static final int STATE_IDLE = 0;
+ private static final int STATE_LISTENING = 1;
+ private static final int STATE_ENROLLING = 2;
+ private static final int STATE_REMOVING = 3;
+ private static final long MS_PER_SEC = 1000;
+ public static final String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
+ public static final String ENROLL_FINGERPRINT = "android.permission.ENROLL_FINGERPRINT";
+
+ private static final class ClientData {
+ public IFingerprintServiceReceiver receiver;
+ int state;
+ int userId;
+ public TokenWatcher tokenWatcher;
+ IBinder getToken() { return tokenWatcher.getToken(); }
+ }
+
+ private class TokenWatcher implements IBinder.DeathRecipient {
+ WeakReference<IBinder> token;
+
+ TokenWatcher(IBinder token) {
+ this.token = new WeakReference<IBinder>(token);
+ }
+
+ IBinder getToken() { return token.get(); }
+ public void binderDied() {
+ mClients.remove(token);
+ this.token = null;
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ if (token != null) {
+ if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token);
+ mClients.remove(token);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+ }
+
+ public FingerprintService(Context context) {
+ super(context);
+ mContext = context;
+ nativeInit(this);
+ }
+
+ // TODO: Move these into separate process
+ // JNI methods to communicate from FingerprintManagerService to HAL
+ native int nativeEnroll(int timeout);
+ native int nativeEnrollCancel();
+ native int nativeRemove(int fingerprintId);
+ native int nativeOpenHal();
+ native int nativeCloseHal();
+ native void nativeInit(FingerprintService service);
+
+ // 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 handleNotify(int msg, int arg1, int arg2) {
+ Slog.v(TAG, "handleNotify(msg=" + msg + ", arg1=" + arg1 + ", arg2=" + arg2 + ")");
+ for (int i = 0; i < mClients.size(); i++) {
+ ClientData clientData = mClients.valueAt(i);
+ if (clientData == null || clientData.receiver == null) {
+ if (DEBUG) Slog.v(TAG, "clientData at " + i + " is invalid!!");
+ continue;
+ }
+ switch (msg) {
+ case FingerprintManager.FINGERPRINT_ERROR: {
+ final int error = arg1;
+ try {
+ clientData.receiver.onError(error);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ mClients.remove(mClients.keyAt(i));
+ }
+ }
+ break;
+ case FingerprintManager.FINGERPRINT_ACQUIRED: {
+ final int acquireInfo = arg1;
+ try {
+ clientData.receiver.onAcquired(acquireInfo);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ mClients.remove(mClients.keyAt(i));
+ }
+ break;
+ }
+ case FingerprintManager.FINGERPRINT_PROCESSED: {
+ final int fingerId = arg1;
+ try {
+ clientData.receiver.onProcessed(fingerId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ mClients.remove(mClients.keyAt(i));
+ }
+ break;
+ }
+ case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
+ final int fingerId = arg1;
+ final int remaining = arg2;
+ if (clientData.state == STATE_ENROLLING) {
+ // Only send enroll updates to clients that are actually enrolling
+ try {
+ clientData.receiver.onEnrollResult(fingerId, remaining);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "can't send message to client. Did it die?", e);
+ mClients.remove(mClients.keyAt(i));
+ }
+ // Update the database with new finger id.
+ // TODO: move to client code (Settings)
+ if (remaining == 0) {
+ FingerprintUtils.addFingerprintIdForUser(fingerId,
+ mContext.getContentResolver(), clientData.userId);
+ clientData.state = STATE_IDLE; // Nothing left to do
+ }
+ } else {
+ if (DEBUG) Slog.w(TAG, "Client not enrolling");
+ break;
+ }
+ break;
+ }
+ 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);
+ if (clientData.receiver != null) {
+ try {
+ clientData.receiver.onRemoved(fingerId);
+ } 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;
+ }
+ break;
+ }
+ }
+ }
+
+ void startEnroll(IBinder token, long timeout, int userId) {
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ clientData.state = STATE_ENROLLING;
+ nativeEnroll((int) (timeout / MS_PER_SEC));
+ } else {
+ Slog.w(TAG, "enroll(): No listener registered");
+ }
+ }
+
+ void startEnrollCancel(IBinder token, int userId) {
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+ clientData.state = STATE_LISTENING;
+ nativeEnrollCancel();
+ } else {
+ Slog.w(TAG, "enrollCancel(): No listener registered");
+ }
+ }
+
+ // Remove all fingerprints for the given user.
+ void startRemove(IBinder token, int fingerId, int userId) {
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ 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);
+ if (result != 0) {
+ Slog.w(TAG, "Error removing fingerprint with id = " + fingerId);
+ }
+ } else {
+ Slog.w(TAG, "remove(" + token + "): No listener registered");
+ }
+ }
+
+ void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId) {
+ if (DEBUG) Slog.v(TAG, "startListening(" + receiver + ")");
+ if (mClients.get(token) == null) {
+ ClientData clientData = new ClientData();
+ clientData.state = STATE_LISTENING;
+ clientData.receiver = receiver;
+ clientData.userId = userId;
+ clientData.tokenWatcher = new TokenWatcher(token);
+ try {
+ token.linkToDeath(clientData.tokenWatcher, 0);
+ mClients.put(token, clientData);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
+ }
+ } else {
+ if (DEBUG) Slog.v(TAG, "listener already registered for " + token);
+ }
+ }
+
+ void removeListener(IBinder token, int userId) {
+ if (DEBUG) Slog.v(TAG, "stopListening(" + token + ")");
+ ClientData clientData = mClients.get(token);
+ if (clientData != null) {
+ token.unlinkToDeath(clientData.tokenWatcher, 0);
+ mClients.remove(token);
+ } else {
+ if (DEBUG) Slog.v(TAG, "listener not registered: " + token);
+ }
+ mClients.remove(token);
+ }
+
+ void checkPermission(String permisison) {
+ // TODO
+ }
+
+ private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+ @Override // Binder call
+ public void enroll(IBinder token, long timeout, int userId) {
+ checkPermission(ENROLL_FINGERPRINT);
+ startEnroll(token, timeout, userId);
+ }
+
+ @Override // Binder call
+ public void enrollCancel(IBinder token,int userId) {
+ checkPermission(ENROLL_FINGERPRINT);
+ startEnrollCancel(token, userId);
+ }
+
+ @Override // Binder call
+ public void remove(IBinder token, int fingerprintId, int userId) {
+ checkPermission(ENROLL_FINGERPRINT); // TODO: Maybe have another permission
+ startRemove(token, fingerprintId, userId);
+ }
+
+ @Override // Binder call
+ public void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId)
+ {
+ checkPermission(USE_FINGERPRINT);
+ addListener(token, receiver, userId);
+ }
+
+ @Override // Binder call
+ public void stopListening(IBinder token, int userId) {
+ checkPermission(USE_FINGERPRINT);
+ removeListener(token, userId);
+ }
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
+ nativeOpenHal();
+ }
+
+}
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
new file mode 100644
index 0000000..23cf40b
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -0,0 +1,122 @@
+/*
+ * 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.server.hdmi;
+
+import android.annotation.Nullable;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.os.RemoteException;
+import android.util.Slog;
+
+/**
+ * Handles CEC command <Active Source>.
+ * <p>
+ * Used by feature actions that need to handle the command in their flow.
+ */
+final class ActiveSourceHandler {
+ private static final String TAG = "ActiveSourceHandler";
+
+ private final HdmiCecLocalDevice mSource;
+ private final HdmiControlService mService;
+ @Nullable
+ private final IHdmiControlCallback mCallback;
+
+ static ActiveSourceHandler create(HdmiCecLocalDevice source,
+ IHdmiControlCallback callback) {
+ if (source == null) {
+ Slog.e(TAG, "Wrong arguments");
+ return null;
+ }
+ return new ActiveSourceHandler(source, callback);
+ }
+
+ private ActiveSourceHandler(HdmiCecLocalDevice source, IHdmiControlCallback callback) {
+ mSource = source;
+ mService = mSource.getService();
+ mCallback = callback;
+ }
+
+ /**
+ * Handles the incoming active source command.
+ *
+ * @param deviceLogicalAddress logical address of the device to be the active source
+ * @param routingPath routing path of the device to be the active source
+ */
+ void process(int deviceLogicalAddress, int routingPath) {
+ if (getSourcePath() == routingPath && mSource.getActiveSource() == getSourceAddress()) {
+ invokeCallback(HdmiCec.RESULT_SUCCESS);
+ return;
+ }
+ HdmiCecDeviceInfo device = mService.getDeviceInfo(deviceLogicalAddress);
+ if (device == null) {
+ // "New device action" initiated by <Active Source> does not require
+ // "Routing change action".
+ mSource.addAndStartAction(new NewDeviceAction(mSource, deviceLogicalAddress,
+ routingPath, false));
+ }
+
+ if (!mSource.isInPresetInstallationMode()) {
+ int prevActiveInput = mSource.getActiveInput();
+ mSource.updateActiveDevice(deviceLogicalAddress, routingPath);
+ if (prevActiveInput != mSource.getActiveInput()) {
+ // TODO: change port input here.
+ }
+ invokeCallback(HdmiCec.RESULT_SUCCESS);
+ } else {
+ // TV is in a mode that should keep its current source/input from
+ // being changed for its operation. Reclaim the active source
+ // or switch the port back to the one used for the current mode.
+ if (mSource.getActiveSource() == getSourceAddress()) {
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(),
+ getSourcePath());
+ mService.sendCecCommand(activeSource);
+ mSource.updateActiveDevice(deviceLogicalAddress, routingPath);
+ invokeCallback(HdmiCec.RESULT_SUCCESS);
+ } else {
+ int activePath = mSource.getActivePath();
+ mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingChange(getSourceAddress(),
+ routingPath, activePath));
+ // TODO: Start port select action here
+ // PortSelectAction action = new PortSelectAction(mService, getSourceAddress(),
+ // activePath, mCallback);
+ // mService.addActionAndStart(action);
+ }
+ }
+ }
+
+ private final int getSourceAddress() {
+ return mSource.getDeviceInfo().getLogicalAddress();
+ }
+
+ private final int getSourcePath() {
+ return mSource.getDeviceInfo().getPhysicalAddress();
+ }
+
+ private void invokeCallback(int result) {
+ if (mCallback == null) {
+ return;
+ }
+ try {
+ mCallback.onComplete(result);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Callback failed:" + e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index e8862c9..02f088f 100644
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -55,9 +55,6 @@
private static final int DEVICE_POLLING_RETRY = 1;
- // TODO: Move this to common place
- private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
-
/**
* Interface used to report result of device discovery.
*/
@@ -75,7 +72,7 @@
private static final class DeviceInfo {
private final int mLogicalAddress;
- private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+ private int mPhysicalAddress = HdmiConstants.INVALID_PHYSICAL_ADDRESS;
private int mVendorId = HdmiCec.UNKNOWN_VENDOR_ID;
private String mDisplayName = "";
private int mDeviceType = HdmiCec.DEVICE_INACTIVE;
@@ -95,14 +92,12 @@
private int mProcessedDeviceCount = 0;
/**
- * @Constructor
+ * Constructor.
*
- * @param service
- * @param sourceAddress
+ * @param source an instance of {@link HdmiCecLocalDevice}.
*/
- DeviceDiscoveryAction(HdmiControlService service, int sourceAddress,
- DeviceDiscoveryCallback callback) {
- super(service, sourceAddress);
+ DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback) {
+ super(source);
mCallback = Preconditions.checkNotNull(callback);
}
@@ -111,7 +106,7 @@
mDevices.clear();
mState = STATE_WAITING_FOR_DEVICE_POLLING;
- mService.pollDevices(new DevicePollingCallback() {
+ pollDevices(new DevicePollingCallback() {
@Override
public void onPollingFinished(List<Integer> ackedAddress) {
if (ackedAddress.isEmpty()) {
@@ -124,7 +119,8 @@
allocateDevices(ackedAddress);
startPhysicalAddressStage();
}
- }, HdmiControlService.POLL_STRATEGY_REMOTES_DEVICES, DEVICE_POLLING_RETRY);
+ }, HdmiConstants.POLL_ITERATION_REVERSE_ORDER
+ | HdmiConstants.POLL_STRATEGY_REMOTES_DEVICES, DEVICE_POLLING_RETRY);
return true;
}
@@ -154,7 +150,12 @@
}
mActionTimer.clearTimerMessage();
- sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(mSourceAddress, address));
+
+ // Check cache first and send request if not exist.
+ if (mayProcessMessageIfCached(address, HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS)) {
+ return;
+ }
+ sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(getSourceAddress(), address));
addTimer(mState, TIMEOUT_MS);
}
@@ -173,7 +174,11 @@
}
mActionTimer.clearTimerMessage();
- sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(mSourceAddress, address));
+
+ if (mayProcessMessageIfCached(address, HdmiCec.MESSAGE_SET_OSD_NAME)) {
+ return;
+ }
+ sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(getSourceAddress(), address));
addTimer(mState, TIMEOUT_MS);
}
@@ -193,10 +198,24 @@
}
mActionTimer.clearTimerMessage();
- sendCommand(HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(mSourceAddress, address));
+
+ if (mayProcessMessageIfCached(address, HdmiCec.MESSAGE_DEVICE_VENDOR_ID)) {
+ return;
+ }
+ sendCommand(
+ HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(getSourceAddress(), address));
addTimer(mState, TIMEOUT_MS);
}
+ private boolean mayProcessMessageIfCached(int address, int opcode) {
+ HdmiCecMessage message = getCecMessageCache().getMessage(address, opcode);
+ if (message != null) {
+ processCommand(message);
+ return true;
+ }
+ return false;
+ }
+
@Override
boolean processCommand(HdmiCecMessage cmd) {
switch (mState) {
@@ -237,7 +256,7 @@
byte params[] = cmd.getParams();
if (params.length == 3) {
- current.mPhysicalAddress = ((params[0] & 0xFF) << 8) | (params[1] & 0xFF);
+ current.mPhysicalAddress = HdmiUtils.twoBytesToInt(params);
current.mDeviceType = params[2] & 0xFF;
increaseProcessedDeviceCount();
@@ -285,9 +304,7 @@
byte[] params = cmd.getParams();
if (params.length == 3) {
- int vendorId = ((params[0] & 0xFF) << 16)
- | ((params[1] & 0xFF) << 8)
- | (params[2] & 0xFF);
+ int vendorId = HdmiUtils.threeBytesToInt(params);
current.mVendorId = vendorId;
} else {
Slog.w(TAG, "Invalid vendor id: " + cmd.toString());
diff --git a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
index 63c2182..51df473 100644
--- a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
@@ -16,9 +16,10 @@
* limitations under the License.
*/
-import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.IHdmiControlCallback;
import android.os.RemoteException;
import android.util.Slog;
@@ -40,18 +41,18 @@
private final int mTargetAddress;
private final IHdmiControlCallback mCallback;
- static DevicePowerStatusAction create(HdmiControlService service, int sourceAddress,
+ static DevicePowerStatusAction create(HdmiCecLocalDevice source,
int targetAddress, IHdmiControlCallback callback) {
- if (service == null || callback == null) {
+ if (source == null || callback == null) {
Slog.e(TAG, "Wrong arguments");
return null;
}
- return new DevicePowerStatusAction(service, sourceAddress, targetAddress, callback);
+ return new DevicePowerStatusAction(source, targetAddress, callback);
}
- private DevicePowerStatusAction(HdmiControlService service, int sourceAddress,
+ private DevicePowerStatusAction(HdmiCecLocalDevice localDevice,
int targetAddress, IHdmiControlCallback callback) {
- super(service, sourceAddress);
+ super(localDevice);
mTargetAddress = targetAddress;
mCallback = callback;
}
@@ -65,8 +66,8 @@
}
private void queryDevicePowerStatus() {
- mService.sendCecCommand(
- HdmiCecMessageBuilder.buildGiveDevicePowerStatus(mSourceAddress, mTargetAddress));
+ sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(),
+ mTargetAddress));
}
@Override
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
new file mode 100644
index 0000000..dbe3b80
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -0,0 +1,225 @@
+/*
+ * 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.server.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.HdmiTvClient;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.RemoteException;
+import android.util.Slog;
+
+/**
+ * Handles an action that selects a logical device as a new active source.
+ *
+ * Triggered by {@link HdmiTvClient}, attempts to select the given target device
+ * for a new active source. It does its best to wake up the target in standby mode
+ * before issuing the command >Set Stream path<.
+ */
+final class DeviceSelectAction extends FeatureAction {
+ private static final String TAG = "DeviceSelect";
+
+ // Time in milliseconds we wait for the device power status to switch to 'Standby'
+ private static final int TIMEOUT_TRANSIT_TO_STANDBY_MS = 5 * 1000;
+
+ // Time in milliseconds we wait for the device power status to turn to 'On'.
+ private static final int TIMEOUT_POWER_ON_MS = 5 * 1000;
+
+ // Time in milliseconds we wait for <Active Source>.
+ private static final int TIMEOUT_ACTIVE_SOURCE_MS = 20 * 1000;
+
+ // The number of times we try to wake up the target device before we give up
+ // and just send <Set Stream Path>.
+ private static final int LOOP_COUNTER_MAX = 20;
+
+ // State in which we wait for <Report Power Status> to come in response to the command
+ // <Give Device Power Status> we have sent.
+ private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 1;
+
+ // State in which we wait for the device power status to switch to 'Standby'.
+ // We wait till the status becomes 'Standby' before we send <Set Stream Path>
+ // to wake up the device again.
+ private static final int STATE_WAIT_FOR_DEVICE_TO_TRANSIT_TO_STANDBY = 2;
+
+ // State in which we wait for the device power status to switch to 'on'. We wait
+ // maximum 100 seconds (20 * 5) before we give up and just send <Set Stream Path>.
+ private static final int STATE_WAIT_FOR_DEVICE_POWER_ON = 3;
+
+ // State in which we wait for the <Active Source> in response to the command
+ // <Set Stream Path> we have sent. We wait as much as TIMEOUT_ACTIVE_SOURCE_MS
+ // before we give up and mark the action as failure.
+ private static final int STATE_WAIT_FOR_ACTIVE_SOURCE = 4;
+
+ private final HdmiCecDeviceInfo mTarget;
+ private final IHdmiControlCallback mCallback;
+
+ private int mPowerStatusCounter = 0;
+
+ /**
+ * Constructor.
+ *
+ * @param source {@link HdmiCecLocalDevice} instance
+ * @param target target logical device that will be a new active source
+ * @param callback callback object
+ */
+ public DeviceSelectAction(HdmiCecLocalDevice source,
+ HdmiCecDeviceInfo target, IHdmiControlCallback callback) {
+ super(source);
+ mCallback = callback;
+ mTarget = target;
+ }
+
+ @Override
+ public boolean start() {
+ // TODO: Call the logic that display a banner saying the select action got started.
+ queryDevicePowerStatus();
+ return true;
+ }
+
+ private void queryDevicePowerStatus() {
+ sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ getSourceAddress(), mTarget.getLogicalAddress()));
+ mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
+ addTimer(mState, TIMEOUT_MS);
+ }
+
+ @Override
+ public boolean processCommand(HdmiCecMessage cmd) {
+ if (cmd.getSource() != mTarget.getLogicalAddress()) {
+ return false;
+ }
+ int opcode = cmd.getOpcode();
+ byte[] params = cmd.getParams();
+
+ switch (mState) {
+ case STATE_WAIT_FOR_REPORT_POWER_STATUS:
+ if (opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS && params.length == 1) {
+ return handleReportPowerStatus(params[0]);
+ }
+ return false;
+ case STATE_WAIT_FOR_ACTIVE_SOURCE:
+ if (opcode == HdmiCec.MESSAGE_ACTIVE_SOURCE && params.length == 2) {
+ int activePath = HdmiUtils.twoBytesToInt(params);
+ ActiveSourceHandler
+ .create(localDevice(), mCallback)
+ .process(cmd.getSource(), activePath);
+ finish();
+ return true;
+ }
+ return false;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ private boolean handleReportPowerStatus(int powerStatus) {
+ // TODO: Check TV's own status which might have been updated during the action.
+ // If in 'Standby' or 'Transit to standby', remove the banner
+ // and stop this action. Otherwise, send <Set Stream Path>
+ switch (powerStatus) {
+ case HdmiCec.POWER_STATUS_ON:
+ sendSetStreamPath();
+ return true;
+ case HdmiCec.POWER_STATUS_TRANSIENT_TO_STANDBY:
+ if (mPowerStatusCounter < 4) {
+ mState = STATE_WAIT_FOR_DEVICE_TO_TRANSIT_TO_STANDBY;
+ addTimer(mState, TIMEOUT_TRANSIT_TO_STANDBY_MS);
+ } else {
+ sendSetStreamPath();
+ }
+ return true;
+ case HdmiCec.POWER_STATUS_STANDBY:
+ if (mPowerStatusCounter == 0) {
+ turnOnDevice();
+ } else {
+ sendSetStreamPath();
+ }
+ return true;
+ case HdmiCec.POWER_STATUS_TRANSIENT_TO_ON:
+ if (mPowerStatusCounter < LOOP_COUNTER_MAX) {
+ mState = STATE_WAIT_FOR_DEVICE_POWER_ON;
+ addTimer(mState, TIMEOUT_POWER_ON_MS);
+ } else {
+ sendSetStreamPath();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private void turnOnDevice() {
+ sendRemoteKeyCommand(HdmiConstants.UI_COMMAND_POWER);
+ sendRemoteKeyCommand(HdmiConstants.UI_COMMAND_POWER_ON_FUNCTION);
+ mState = STATE_WAIT_FOR_DEVICE_POWER_ON;
+ addTimer(mState, TIMEOUT_POWER_ON_MS);
+ }
+
+ private void sendSetStreamPath() {
+ sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(
+ getSourceAddress(), mTarget.getPhysicalAddress()));
+ mState = STATE_WAIT_FOR_ACTIVE_SOURCE;
+ addTimer(mState, TIMEOUT_ACTIVE_SOURCE_MS);
+ }
+
+ private void sendRemoteKeyCommand(int keyCode) {
+ sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(),
+ mTarget.getLogicalAddress(), keyCode));
+ sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(getSourceAddress(),
+ mTarget.getLogicalAddress()));
+ }
+
+ @Override
+ public void handleTimerEvent(int timeoutState) {
+ if (mState != timeoutState) {
+ Slog.w(TAG, "Timer in a wrong state. Ignored.");
+ return;
+ }
+ switch (mState) {
+ case STATE_WAIT_FOR_REPORT_POWER_STATUS:
+ sendSetStreamPath();
+ break;
+ case STATE_WAIT_FOR_DEVICE_TO_TRANSIT_TO_STANDBY:
+ case STATE_WAIT_FOR_DEVICE_POWER_ON:
+ mPowerStatusCounter++;
+ queryDevicePowerStatus();
+ break;
+ case STATE_WAIT_FOR_ACTIVE_SOURCE:
+ // TODO: Remove the banner
+ // Display banner "Communication failed. Please check your cable or connection"
+ invokeCallback(HdmiCec.RESULT_TIMEOUT);
+ finish();
+ break;
+ }
+ }
+
+ private void invokeCallback(int result) {
+ if (mCallback == null) {
+ return;
+ }
+ try {
+ mCallback.onComplete(result);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Callback failed:" + e);
+ }
+ }
+
+ int getTargetAddress() {
+ return mTarget.getLogicalAddress();
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/FeatureAction.java b/services/core/java/com/android/server/hdmi/FeatureAction.java
index 0ba7773..0ec17f6 100644
--- a/services/core/java/com/android/server/hdmi/FeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/FeatureAction.java
@@ -22,6 +22,9 @@
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.hdmi.HdmiControlService.DevicePollingCallback;
+
+import java.util.List;
/**
* Encapsulates a sequence of CEC/MHL command exchange for a certain feature.
@@ -33,21 +36,21 @@
* of the object. All the actual action classes inherit FeatureAction.
*
* <p>More than one FeatureAction objects can be up and running simultaneously,
- * maintained by {@link HdmiControlService}. Each action is passed a new command
+ * maintained by {@link HdmiCecLocalDevice}. Each action is passed a new command
* arriving from the bus, and either consumes it if the command is what the action expects,
* or yields it to other action.
*
* Declared as package private, accessed by {@link HdmiControlService} only.
*/
abstract class FeatureAction {
-
private static final String TAG = "FeatureAction";
// Timer handler message used for timeout event
protected static final int MSG_TIMEOUT = 100;
- // Default timeout for the incoming command to arrive in response to a request
- protected static final int TIMEOUT_MS = 1000;
+ // Default timeout for the incoming command to arrive in response to a request.
+ // TODO: Consider reading this value from configuration to allow customization.
+ protected static final int TIMEOUT_MS = 2000;
// Default state used in common by all the feature actions.
protected static final int STATE_NONE = 0;
@@ -55,19 +58,16 @@
// Internal state indicating the progress of action.
protected int mState = STATE_NONE;
- protected final HdmiControlService mService;
-
- // Logical address of the device for which the feature action is taken. The commands
- // generated in an action all use this field as source address.
- protected final int mSourceAddress;
+ private final HdmiControlService mService;
+ private final HdmiCecLocalDevice mSource;
// Timer that manages timeout events.
protected ActionTimer mActionTimer;
- FeatureAction(HdmiControlService service, int sourceAddress) {
- mService = service;
- mSourceAddress = sourceAddress;
- mActionTimer = createActionTimer(service.getServiceLooper());
+ FeatureAction(HdmiCecLocalDevice source) {
+ mSource = source;
+ mService = mSource.getService();
+ mActionTimer = createActionTimer(mService.getServiceLooper());
}
@VisibleForTesting
@@ -174,6 +174,42 @@
mService.sendCecCommand(cmd, callback);
}
+ protected final void addAndStartAction(FeatureAction action) {
+ mSource.addAndStartAction(action);
+ }
+
+ protected final <T extends FeatureAction> List<T> getActions(final Class<T> clazz) {
+ return mSource.getActions(clazz);
+ }
+
+ protected final HdmiCecMessageCache getCecMessageCache() {
+ return mSource.getCecMessageCache();
+ }
+
+ /**
+ * Remove the action from the action queue. This is called after the action finishes
+ * its role.
+ *
+ * @param action
+ */
+ protected final void removeAction(FeatureAction action) {
+ mSource.removeAction(action);
+ }
+
+ protected final <T extends FeatureAction> void removeAction(final Class<T> clazz) {
+ mSource.removeActionExcept(clazz, null);
+ }
+
+ protected final <T extends FeatureAction> void removeActionExcept(final Class<T> clazz,
+ final FeatureAction exception) {
+ mSource.removeActionExcept(clazz, exception);
+ }
+
+ protected final void pollDevices(DevicePollingCallback callback, int pickStrategy,
+ int retryCount) {
+ mService.pollDevices(callback, pickStrategy, retryCount);
+ }
+
/**
* Clean up action's state.
*
@@ -193,13 +229,23 @@
removeAction(this);
}
- /**
- * Remove the action from the action queue. This is called after the action finishes
- * its role.
- *
- * @param action
- */
- private void removeAction(FeatureAction action) {
- mService.removeAction(action);
+ protected final HdmiCecLocalDevice localDevice() {
+ return mSource;
+ }
+
+ protected final HdmiCecLocalDevicePlayback playback() {
+ return (HdmiCecLocalDevicePlayback) mSource;
+ }
+
+ protected final HdmiCecLocalDeviceTv tv() {
+ return (HdmiCecLocalDeviceTv) mSource;
+ }
+
+ protected final int getSourceAddress() {
+ return mSource.getDeviceInfo().getLogicalAddress();
+ }
+
+ protected final int getSourcePath() {
+ return mSource.getDeviceInfo().getPhysicalAddress();
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 5c420d7..6d05e82 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -17,8 +17,8 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiCec;
-import android.hardware.hdmi.HdmiCecDeviceInfo;
import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.HdmiPortInfo;
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
@@ -108,10 +108,6 @@
private HdmiControlService mService;
- // Map-like container of all cec devices including local ones.
- // A logical address of device is used as key of container.
- private final SparseArray<HdmiCecDeviceInfo> mDeviceInfos = new SparseArray<>();
-
// Stores the local CEC devices in the system. Device type is used for key.
private final SparseArray<HdmiCecLocalDevice> mLocalDevices = new SparseArray<>();
@@ -223,89 +219,9 @@
return body;
}
- /**
- * Add a new {@link HdmiCecDeviceInfo}. It returns old device info which has the same
- * logical address as new device info's.
- *
- * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
- *
- * @param deviceInfo a new {@link HdmiCecDeviceInfo} to be added.
- * @return {@code null} if it is new device. Otherwise, returns old {@HdmiCecDeviceInfo}
- * that has the same logical address as new one has.
- */
- HdmiCecDeviceInfo addDeviceInfo(HdmiCecDeviceInfo deviceInfo) {
- assertRunOnServiceThread();
- HdmiCecDeviceInfo oldDeviceInfo = getDeviceInfo(deviceInfo.getLogicalAddress());
- if (oldDeviceInfo != null) {
- removeDeviceInfo(deviceInfo.getLogicalAddress());
- }
- mDeviceInfos.append(deviceInfo.getLogicalAddress(), deviceInfo);
- return oldDeviceInfo;
- }
- /**
- * Remove a device info corresponding to the given {@code logicalAddress}.
- * It returns removed {@link HdmiCecDeviceInfo} if exists.
- *
- * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
- *
- * @param logicalAddress logical address of device to be removed
- * @return removed {@link HdmiCecDeviceInfo} it exists. Otherwise, returns {@code null}
- */
- HdmiCecDeviceInfo removeDeviceInfo(int logicalAddress) {
- assertRunOnServiceThread();
- HdmiCecDeviceInfo deviceInfo = mDeviceInfos.get(logicalAddress);
- if (deviceInfo != null) {
- mDeviceInfos.remove(logicalAddress);
- }
- return deviceInfo;
- }
-
- /**
- * Clear all device info.
- *
- * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
- */
- void clearDeviceInfoList() {
- assertRunOnServiceThread();
- mDeviceInfos.clear();
- }
-
- /**
- * Return a list of all {@link HdmiCecDeviceInfo}.
- *
- * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
- *
- * @param includeLocalDevice whether to add local device or not
- */
- List<HdmiCecDeviceInfo> getDeviceInfoList(boolean includeLocalDevice) {
- assertRunOnServiceThread();
- if (includeLocalDevice) {
- return sparseArrayToList(mDeviceInfos);
- } else {
- ArrayList<HdmiCecDeviceInfo> infoList = new ArrayList<>();
- for (int i = 0; i < mDeviceInfos.size(); ++i) {
- HdmiCecDeviceInfo info = mDeviceInfos.valueAt(i);
- if (mRemoteDeviceAddressPredicate.apply(info.getLogicalAddress())) {
- infoList.add(info);
- }
- }
- return infoList;
- }
- }
-
- /**
- * Return a {@link HdmiCecDeviceInfo} corresponding to the given {@code logicalAddress}.
- *
- * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
- *
- * @param logicalAddress logical address to be retrieved
- * @return {@link HdmiCecDeviceInfo} matched with the given {@code logicalAddress}.
- * Returns null if no logical address matched
- */
- HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) {
- assertRunOnServiceThread();
- return mDeviceInfos.get(logicalAddress);
+ HdmiPortInfo[] getPortInfos() {
+ return nativeGetPortInfos(mNativePtr);
}
/**
@@ -387,6 +303,41 @@
}
/**
+ * Pass a option to CEC HAL.
+ *
+ * @param flag a key of option. For more details, look at
+ * {@link HdmiConstants#FLAG_HDMI_OPTION_WAKEUP} to
+ * {@link HdmiConstants#FLAG_HDMI_OPTION_SYSTEM_CEC_CONTROL}
+ * @param value a value of option. Actual value varies flag. For more
+ * details, look at description of flags
+ */
+ void setOption(int flag, int value) {
+ assertRunOnServiceThread();
+ nativeSetOption(mNativePtr, flag, value);
+ }
+
+ /**
+ * Configure ARC circuit in the hardware logic to start or stop the feature.
+ *
+ * @param enabled whether to enable/disable ARC
+ */
+ void setAudioReturnChannel(boolean enabled) {
+ assertRunOnServiceThread();
+ nativeSetAudioReturnChannel(mNativePtr, enabled);
+ }
+
+ /**
+ * Return the connection status of the specified port
+ *
+ * @param port port number to check connection status
+ * @return true if connected; otherwise, return false
+ */
+ boolean isConnected(int port) {
+ assertRunOnServiceThread();
+ return nativeIsConnected(mNativePtr, port);
+ }
+
+ /**
* Poll all remote devices. It sends <Polling Message> to all remote
* devices.
*
@@ -411,33 +362,33 @@
*/
List<HdmiCecLocalDevice> getLocalDeviceList() {
assertRunOnServiceThread();
- return sparseArrayToList(mLocalDevices);
+ return HdmiUtils.sparseArrayToList(mLocalDevices);
}
private List<Integer> pickPollCandidates(int pickStrategy) {
- int strategy = pickStrategy & HdmiControlService.POLL_STRATEGY_MASK;
+ int strategy = pickStrategy & HdmiConstants.POLL_STRATEGY_MASK;
Predicate<Integer> pickPredicate = null;
switch (strategy) {
- case HdmiControlService.POLL_STRATEGY_SYSTEM_AUDIO:
+ case HdmiConstants.POLL_STRATEGY_SYSTEM_AUDIO:
pickPredicate = mSystemAudioAddressPredicate;
break;
- case HdmiControlService.POLL_STRATEGY_REMOTES_DEVICES:
+ case HdmiConstants.POLL_STRATEGY_REMOTES_DEVICES:
default: // The default is POLL_STRATEGY_REMOTES_DEVICES.
pickPredicate = mRemoteDeviceAddressPredicate;
break;
}
- int iterationStrategy = pickStrategy & HdmiControlService.POLL_ITERATION_STRATEGY_MASK;
+ int iterationStrategy = pickStrategy & HdmiConstants.POLL_ITERATION_STRATEGY_MASK;
ArrayList<Integer> pollingCandidates = new ArrayList<>();
switch (iterationStrategy) {
- case HdmiControlService.POLL_ITERATION_IN_ORDER:
+ case HdmiConstants.POLL_ITERATION_IN_ORDER:
for (int i = HdmiCec.ADDR_TV; i <= HdmiCec.ADDR_SPECIFIC_USE; ++i) {
if (pickPredicate.apply(i)) {
pollingCandidates.add(i);
}
}
break;
- case HdmiControlService.POLL_ITERATION_REVERSE_ORDER:
+ case HdmiConstants.POLL_ITERATION_REVERSE_ORDER:
default: // The default is reverse order.
for (int i = HdmiCec.ADDR_SPECIFIC_USE; i >= HdmiCec.ADDR_TV; --i) {
if (pickPredicate.apply(i)) {
@@ -449,14 +400,6 @@
return pollingCandidates;
}
- private static <T> List<T> sparseArrayToList(SparseArray<T> array) {
- ArrayList<T> list = new ArrayList<>();
- for (int i = 0; i < array.size(); ++i) {
- list.add(array.valueAt(i));
- }
- return list;
- }
-
private boolean isAllocatedLocalDeviceAddress(int address) {
for (int i = 0; i < mLocalDevices.size(); ++i) {
if (mLocalDevices.valueAt(i).isAddressOf(address)) {
@@ -499,7 +442,7 @@
// new logical address for the device because no device uses
// it as logical address of the device.
if (nativeSendCecCommand(mNativePtr, address, address, EMPTY_BODY)
- == HdmiControlService.SEND_RESULT_SUCCESS) {
+ == HdmiConstants.SEND_RESULT_SUCCESS) {
return true;
}
}
@@ -566,7 +509,7 @@
byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
final int error = nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
cecMessage.getDestination(), body);
- if (error != HdmiControlService.SEND_RESULT_SUCCESS) {
+ if (error != HdmiConstants.SEND_RESULT_SUCCESS) {
Slog.w(TAG, "Failed to send " + cecMessage);
}
if (callback != null) {
@@ -606,4 +549,8 @@
private static native int nativeGetPhysicalAddress(long controllerPtr);
private static native int nativeGetVersion(long controllerPtr);
private static native int nativeGetVendorId(long controllerPtr);
+ private static native HdmiPortInfo[] nativeGetPortInfos(long controllerPtr);
+ private static native void nativeSetOption(long controllerPtr, int flag, int value);
+ private static native void nativeSetAudioReturnChannel(long controllerPtr, boolean flag);
+ private static native boolean nativeIsConnected(long controllerPtr, int port);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
deleted file mode 100644
index baae1d9..0000000
--- a/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
+++ /dev/null
@@ -1,230 +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.server.hdmi;
-
-import android.hardware.hdmi.HdmiCec;
-import android.hardware.hdmi.HdmiCecMessage;
-import android.hardware.hdmi.IHdmiCecListener;
-import android.os.Binder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * HdmiCecDevice class represents a CEC logical device characterized
- * by its device type. It is a superclass of those serving concrete device type.
- * Currently we're interested in playback(one of sources), display(sink) device type
- * only. The support for the other types like recorder, audio system will come later.
- *
- * <p>A physical device can contain the functions of
- * more than one logical device, in which case it should create
- * as many logical devices as necessary.
- *
- * <p>Note that if a physical device has multiple instances of a particular
- * functionality, it should advertize only one instance. For instance, if
- * a device has multiple tuners, it should only expose one for control
- * via CEC. In this case, it is up to the device itself to manage multiple tuners.
- *
- * <p>The version of HDMI-CEC protocol supported in this class is 1.3a.
- *
- * <p>Declared as package-private, accessed by HdmiCecService only.
- */
-abstract class HdmiCecDevice {
- private static final String TAG = "HdmiCecDevice";
-
- private final int mType;
-
- // List of listeners to the message/event coming to the device.
- private final List<IHdmiCecListener> mListeners = new ArrayList<IHdmiCecListener>();
- private final Binder mBinder = new Binder();
- private final HdmiCecService mService;
-
- private boolean mIsActiveSource;
-
- /**
- * Factory method that creates HdmiCecDevice instance to the device type.
- */
- public static HdmiCecDevice create(HdmiCecService service, int type) {
- if (type == HdmiCec.DEVICE_PLAYBACK) {
- return new HdmiCecDevicePlayback(service, type);
- } else if (type == HdmiCec.DEVICE_TV) {
- return new HdmiCecDeviceTv(service, type);
- }
- return null;
- }
-
- /**
- * Constructor.
- */
- public HdmiCecDevice(HdmiCecService service, int type) {
- mService = service;
- mType = type;
- mIsActiveSource = false;
- }
-
- /**
- * Called right after the class is instantiated. This method can be used to
- * implement any initialization tasks for the instance.
- */
- abstract public void initialize();
-
- /**
- * Return the binder token that identifies this instance.
- */
- public Binder getToken() {
- return mBinder;
- }
-
- /**
- * Return the service instance.
- */
- public HdmiCecService getService() {
- return mService;
- }
-
- /**
- * Return the type of this device.
- */
- public int getType() {
- return mType;
- }
-
- /**
- * Register a listener to be invoked when events occur.
- *
- * @param listener the listern that will run
- */
- public void addListener(IHdmiCecListener listener) {
- mListeners.add(listener);
- }
-
- /**
- * Remove the listener that was previously registered.
- *
- * @param listener IHdmiCecListener instance to be removed
- */
- public void removeListener(IHdmiCecListener listener) {
- mListeners.remove(listener);
- }
-
- /**
- * Indicate if the device has listeners.
- *
- * @return true if there are listener instances for this device
- */
- public boolean hasListener() {
- return !mListeners.isEmpty();
- }
-
- /**
- * Handle HDMI-CEC message coming to the device by invoking the registered
- * listeners.
- */
- public void handleMessage(int srcAddress, int dstAddress, int opcode, byte[] params) {
- if (opcode == HdmiCec.MESSAGE_ACTIVE_SOURCE) {
- mIsActiveSource = false;
- }
-
- if (mListeners.size() == 0) {
- return;
- }
- HdmiCecMessage message = new HdmiCecMessage(srcAddress, dstAddress, opcode, params);
- for (IHdmiCecListener listener : mListeners) {
- try {
- listener.onMessageReceived(message);
- } catch (RemoteException e) {
- Log.e(TAG, "listener.onMessageReceived failed.");
- }
- }
- }
-
- public void handleHotplug(boolean connected) {
- for (IHdmiCecListener listener : mListeners) {
- try {
- listener.onCableStatusChanged(connected);
- } catch (RemoteException e) {
- Log.e(TAG, "listener.onCableStatusChanged failed.");
- }
- }
- }
-
- /**
- * Return the active status of the device.
- *
- * @return true if the device is the active source among the connected
- * HDMI-CEC-enabled devices; otherwise false.
- */
- public boolean isActiveSource() {
- return mIsActiveSource;
- }
-
- /**
- * Update the active source state of the device.
- */
- public void setIsActiveSource(boolean state) {
- mIsActiveSource = state;
- }
-
- /**
- * Send <Active Source> command. The default implementation does nothing. Should be
- * overriden by subclass.
- */
- public void sendActiveSource(int physicalAddress) {
- logWarning("<Active Source> not valid for the device type: " + mType
- + " address:" + physicalAddress);
- }
-
- /**
- * Send <Inactive Source> command. The default implementation does nothing. Should be
- * overriden by subclass.
- */
- public void sendInactiveSource(int physicalAddress) {
- logWarning("<Inactive Source> not valid for the device type: " + mType
- + " address:" + physicalAddress);
- }
-
- /**
- * Send <Image View On> command. The default implementation does nothing. Should be
- * overriden by subclass.
- */
- public void sendImageViewOn() {
- logWarning("<Image View On> not valid for the device type: " + mType);
- }
-
- /**
- * Send <Text View On> command. The default implementation does nothing. Should be
- * overriden by subclass.
- */
- public void sendTextViewOn() {
- logWarning("<Text View On> not valid for the device type: " + mType);
- }
-
- /**
- * Check if the connected sink device is in powered-on state. The default implementation
- * simply returns false. Should be overriden by subclass to report the correct state.
- */
- public boolean isSinkDeviceOn() {
- logWarning("isSinkDeviceOn() not valid for the device type: " + mType);
- return false;
- }
-
- private void logWarning(String msg) {
- Log.w(TAG, msg);
- }
-}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
deleted file mode 100644
index f8cf11d..0000000
--- a/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
+++ /dev/null
@@ -1,129 +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.server.hdmi;
-
-import android.hardware.hdmi.HdmiCec;
-
-/**
- * Class for the logical device of playback type. Devices such as DVD/Blueray player
- * that support 'playback' feature are classified as playback device. It is common
- * that they don't have built-in display, therefore need to talk, stream their contents
- * to TV/display device which is connected through HDMI cable.
- *
- * <p>It closely monitors the status of display device (other devices can be of interest
- * too, but with much less priority), declares itself as 'active source' to have
- * display show its output, switch the source state as ordered by display that may be
- * talking to many other devices connected to it. It also receives commands from display
- * such as remote control signal, standby, status report, playback mode.
- *
- * <p>Declared as package-private, accessed by HdmiCecService only.
- */
-final class HdmiCecDevicePlayback extends HdmiCecDevice {
- private static final String TAG = "HdmiCecDevicePlayback";
-
- private int mSinkDevicePowerStatus;
-
- /**
- * Constructor.
- */
- public HdmiCecDevicePlayback(HdmiCecService service, int type) {
- super(service, type);
- mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_UNKNOWN;
- }
-
- @Override
- public void initialize() {
- // Playback device tries to obtain the power status of TV/display when created,
- // and maintains it all through its lifecycle. CEC spec says there is
- // a maximum 1 second response time. Therefore it should be kept in mind
- // that there can be as much amount of period of time the power status
- // of the display remains unknown after the query is sent out.
- queryTvPowerStatus();
- }
-
- private void queryTvPowerStatus() {
- getService().sendMessage(getType(), HdmiCec.ADDR_TV,
- HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, HdmiCecService.EMPTY_PARAM);
- }
-
- @Override
- public void handleMessage(int srcAddress, int dstAddress, int opcode, byte[] params) {
- // Updates power status of display. The cases are:
- // 1) Response for the queried power status request arrives. Update the status.
- // 2) Broadcast or direct <Standby> command from TV, which is sent as TV itself is going
- // into standby mode too.
- if (opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS) {
- mSinkDevicePowerStatus = params[0];
- } else if (srcAddress == HdmiCec.ADDR_TV) {
- if (opcode == HdmiCec.MESSAGE_STANDBY) {
- mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_STANDBY;
- }
- }
- super.handleMessage(srcAddress, dstAddress, opcode, params);
- }
-
- @Override
- public void handleHotplug(boolean connected) {
- // If cable get disconnected sink device becomes unreachable. Switch the status
- // to unknown, and query the status once the cable gets connected back.
- if (!connected) {
- mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_UNKNOWN;
- } else {
- queryTvPowerStatus();
- }
- super.handleHotplug(connected);
- }
-
- @Override
- public boolean isSinkDeviceOn() {
- return mSinkDevicePowerStatus == HdmiCec.POWER_STATUS_ON;
- }
-
- @Override
- public void sendActiveSource(int physicalAddress) {
- setIsActiveSource(true);
- byte[] param = new byte[] {
- (byte) ((physicalAddress >> 8) & 0xff),
- (byte) (physicalAddress & 0xff)
- };
- getService().sendMessage(getType(), HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_ACTIVE_SOURCE,
- param);
- }
-
- @Override
- public void sendInactiveSource(int physicalAddress) {
- setIsActiveSource(false);
- byte[] param = new byte[] {
- (byte) ((physicalAddress >> 8) & 0xff),
- (byte) (physicalAddress & 0xff)
- };
- getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_INACTIVE_SOURCE,
- param);
- }
-
- @Override
- public void sendImageViewOn() {
- getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_IMAGE_VIEW_ON,
- HdmiCecService.EMPTY_PARAM);
- }
-
- @Override
- public void sendTextViewOn() {
- getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_TEXT_VIEW_ON,
- HdmiCecService.EMPTY_PARAM);
- }
-}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecDeviceTv.java
deleted file mode 100644
index 09ff3ca..0000000
--- a/services/core/java/com/android/server/hdmi/HdmiCecDeviceTv.java
+++ /dev/null
@@ -1,35 +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.server.hdmi;
-
-/**
- * Class for logical device of TV type.
- */
-final class HdmiCecDeviceTv extends HdmiCecDevice {
- private static final String TAG = "HdmiCecDeviceTv";
-
- /**
- * Constructor.
- */
- public HdmiCecDeviceTv(HdmiCecService service, int type) {
- super(service, type);
- }
-
- public void initialize() {
- // TODO: Do the initialization task for TV device here.
- }
-}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
new file mode 100644
index 0000000..7080a56
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
@@ -0,0 +1,349 @@
+/*
+ * 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.server.hdmi;
+
+import android.view.KeyEvent;
+
+/**
+ * Helper class to translate android keycode to hdmi cec keycode and vice versa.
+ */
+public class HdmiCecKeycode {
+ public static final int UNSUPPORTED_KEYCODE = -1;
+ public static final int NO_PARAM = -1;
+
+ // =========================================================================
+ // Hdmi CEC keycodes
+ public static final int CEC_KEYCODE_SELECT = 0x00;
+ public static final int CEC_KEYCODE_UP = 0x01;
+ public static final int CEC_KEYCODE_DOWN = 0x02;
+ public static final int CEC_KEYCODE_LEFT = 0x03;
+ public static final int CEC_KEYCODE_RIGHT = 0x04;
+ public static final int CEC_KEYCODE_RIGHT_UP = 0x05;
+ public static final int CEC_KEYCODE_RIGHT_DOWN = 0x06;
+ public static final int CEC_KEYCODE_LEFT_UP = 0x07;
+ public static final int CEC_KEYCODE_LEFT_DOWN = 0x08;
+ public static final int CEC_KEYCODE_ROOT_MENU = 0x09;
+ public static final int CEC_KEYCODE_SETUP_MENU = 0x0A;
+ public static final int CEC_KEYCODE_CONTENTS_MENU = 0x0B;
+ public static final int CEC_KEYCODE_FAVORITE_MENU = 0x0C;
+ public static final int CEC_KEYCODE_EXIT = 0x0D;
+ // RESERVED = 0x0E - 0x0F
+ public static final int CEC_KEYCODE_MEDIA_TOP_MENU = 0x10;
+ public static final int CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU = 0x11;
+ // RESERVED = 0x12 – 0x1C
+ public static final int CEC_KEYCODE_NUMBER_ENTRY_MODE = 0x1D;
+ public static final int CEC_KEYCODE_NUMBER_11 = 0x1E;
+ public static final int CEC_KEYCODE_NUMBER_12 = 0x1F;
+ public static final int CEC_KEYCODE_NUMBER_0_OR_NUMBER_10 = 0x20;
+ public static final int CEC_KEYCODE_NUMBERS_1 = 0x21;
+ public static final int CEC_KEYCODE_NUMBERS_2 = 0x22;
+ public static final int CEC_KEYCODE_NUMBERS_3 = 0x23;
+ public static final int CEC_KEYCODE_NUMBERS_4 = 0x24;
+ public static final int CEC_KEYCODE_NUMBERS_5 = 0x25;
+ public static final int CEC_KEYCODE_NUMBERS_6 = 0x26;
+ public static final int CEC_KEYCODE_NUMBERS_7 = 0x27;
+ public static final int CEC_KEYCODE_NUMBERS_8 = 0x28;
+ public static final int CEC_KEYCODE_NUMBERS_9 = 0x29;
+ public static final int CEC_KEYCODE_DOT = 0x2A;
+ public static final int CEC_KEYCODE_ENTER = 0x2B;
+ public static final int CEC_KEYCODE_CLEAR = 0x2C;
+ // RESERVED = 0x2D - 0x2E
+ public static final int CEC_KEYCODE_NEXT_FAVORITE = 0x2F;
+ public static final int CEC_KEYCODE_CHANNEL_UP = 0x30;
+ public static final int CEC_KEYCODE_CHANNEL_DOWN = 0x31;
+ public static final int CEC_KEYCODE_PREVIOUS_CHANNEL = 0x32;
+ public static final int CEC_KEYCODE_SOUND_SELECT = 0x33;
+ public static final int CEC_KEYCODE_INPUT_SELECT = 0x34;
+ public static final int CEC_KEYCODE_DISPLAY_INFORMATION = 0x35;
+ public static final int CEC_KEYCODE_HELP = 0x36;
+ public static final int CEC_KEYCODE_PAGE_UP = 0x37;
+ public static final int CEC_KEYCODE_PAGE_DOWN = 0x38;
+ // RESERVED = 0x39 - 0x3F
+ public static final int CEC_KEYCODE_POWER = 0x40;
+ public static final int CEC_KEYCODE_VOLUME_UP = 0x41;
+ public static final int CEC_KEYCODE_VOLUME_DOWN = 0x42;
+ public static final int CEC_KEYCODE_MUTE = 0x43;
+ public static final int CEC_KEYCODE_PLAY = 0x44;
+ public static final int CEC_KEYCODE_STOP = 0x45;
+ public static final int CEC_KEYCODE_PAUSE = 0x46;
+ public static final int CEC_KEYCODE_RECORD = 0x47;
+ public static final int CEC_KEYCODE_REWIND = 0x48;
+ public static final int CEC_KEYCODE_FAST_FORWARD = 0x49;
+ public static final int CEC_KEYCODE_EJECT = 0x4A;
+ public static final int CEC_KEYCODE_FORWARD = 0x4B;
+ public static final int CEC_KEYCODE_BACKWARD = 0x4C;
+ public static final int CEC_KEYCODE_STOP_RECORD = 0x4D;
+ public static final int CEC_KEYCODE_PAUSE_RECORD = 0x4E;
+ public static final int CEC_KEYCODE_RESERVED = 0x4F;
+ public static final int CEC_KEYCODE_ANGLE = 0x50;
+ public static final int CEC_KEYCODE_SUB_PICTURE = 0x51;
+ public static final int CEC_KEYCODE_VIDEO_ON_DEMAND = 0x52;
+ public static final int CEC_KEYCODE_ELECTRONIC_PROGRAM_GUIDE = 0x53;
+ public static final int CEC_KEYCODE_TIMER_PROGRAMMING = 0x54;
+ public static final int CEC_KEYCODE_INITIAL_CONFIGURATION = 0x55;
+ public static final int CEC_KEYCODE_SELECT_BROADCAST_TYPE = 0x56;
+ public static final int CEC_KEYCODE_SELECT_SOUND_PRESENTATION = 0x57;
+ // RESERVED = 0x58-0x5F
+ public static final int CEC_KEYCODE_PLAY_FUNCTION = 0x60;
+ public static final int CEC_KEYCODE_PAUSE_PLAY_FUNCTION = 0x61;
+ public static final int CEC_KEYCODE_RECORD_FUNCTION = 0x62;
+ public static final int CEC_KEYCODE_PAUSE_RECORD_FUNCTION = 0x63;
+ public static final int CEC_KEYCODE_STOP_FUNCTION = 0x64;
+ public static final int CEC_KEYCODE_MUTE_FUNCTION = 0x65;
+ public static final int CEC_KEYCODE_RESTORE_VOLUME_FUNCTION = 0x66;
+ public static final int CEC_KEYCODE_TUNE_FUNCTION = 0x67;
+ public static final int CEC_KEYCODE_SELECT_MEDIA_FUNCTION = 0x68;
+ public static final int CEC_KEYCODE_SELECT_AV_INPUT_FUNCTION = 0x69;
+ public static final int CEC_KEYCODE_SELECT_AUDIO_INPUT_FUNCTION = 0x6A;
+ public static final int CEC_KEYCODE_POWER_TOGGLE_FUNCTION = 0x6B;
+ public static final int CEC_KEYCODE_POWER_OFF_FUNCTION = 0x6C;
+ public static final int CEC_KEYCODE_POWER_ON_FUNCTION = 0x6D;
+ // RESERVED = 0x6E-0x70
+ public static final int CEC_KEYCODE_F1_BLUE = 0x71;
+ public static final int CEC_KEYCODE_F2_RED = 0x72;
+ public static final int CEC_KEYCODE_F3_GREEN = 0x73;
+ public static final int CEC_KEYCODE_F4_YELLOW = 0x74;
+ public static final int CEC_KEYCODE_F5 = 0x75;
+ public static final int CEC_KEYCODE_DATA = 0x76;
+ // RESERVED = 0x77-0xFF
+
+ // =========================================================================
+ // UI Broadcast Type
+ public static final int UI_BROADCAST_TOGGLE_ALL = 0x00;
+ public static final int UI_BROADCAST_TOGGLE_ANALOGUE_DIGITAL = 0x01;
+ public static final int UI_BROADCAST_ANALOGUE = 0x10;
+ public static final int UI_BROADCAST_ANALOGUE_TERRESTRIAL = 0x20;
+ public static final int UI_BROADCAST_ANALOGUE_CABLE = 0x30;
+ public static final int UI_BROADCAST_ANALOGUE_SATELLITE = 0x40;
+ public static final int UI_BROADCAST_DIGITAL = 0x50;
+ public static final int UI_BROADCAST_DIGITAL_TERRESTRIAL = 0x60;
+ public static final int UI_BROADCAST_DIGITAL_CABLE = 0x70;
+ public static final int UI_BROADCAST_DIGITAL_SATELLITE = 0x80;
+ public static final int UI_BROADCAST_DIGITAL_COMMNICATIONS_SATELLITE = 0x90;
+ public static final int UI_BROADCAST_DIGITAL_COMMNICATIONS_SATELLITE_2 = 0x91;
+ public static final int UI_BROADCAST_IP = 0xA0;
+
+ // =========================================================================
+ // UI Sound Presentation Control
+ public static final int UI_SOUND_PRESENTATION_SOUND_MIX_DUAL_MONO = 0x20;
+ public static final int UI_SOUND_PRESENTATION_SOUND_MIX_KARAOKE = 0x30;
+ public static final int UI_SOUND_PRESENTATION_SELECT_AUDIO_DOWN_MIX = 0x80;
+ public static final int UI_SOUND_PRESENTATION_SELECT_AUDIO_AUTO_REVERBERATION = 0x90;
+ public static final int UI_SOUND_PRESENTATION_SELECT_AUDIO_AUTO_EQUALIZER = 0xA0;
+ public static final int UI_SOUND_PRESENTATION_BASS_STEP_PLUS = 0xB1;
+ public static final int UI_SOUND_PRESENTATION_BASS_NEUTRAL = 0xB2;
+ public static final int UI_SOUND_PRESENTATION_BASS_STEP_MINUS = 0xB3;
+ public static final int UI_SOUND_PRESENTATION_TREBLE_STEP_PLUS = 0xC1;
+ public static final int UI_SOUND_PRESENTATION_TREBLE_NEUTRAL = 0xC2;
+ public static final int UI_SOUND_PRESENTATION_TREBLE_STEP_MINUS = 0xC3;
+
+ private HdmiCecKeycode() {
+ }
+
+ /**
+ * A mapping between andorid and cec keycode.
+ *
+ * <p>Normal implementation of this looks like
+ * <pre>
+ * new KeycodeEntry(KeyEvent.KEYCODE_DPAD_CENTER, CEC_KEYCODE_SELECT);
+ * </pre>
+ * <p>However, some keys in CEC requires additional parameter.
+ * In order to use parameterized cec key, add unique android keycode (existing or custom)
+ * corresponding to a pair of cec keycode and and its param.
+ * <pre>
+ * new KeycodeEntry(CUSTOME_ANDORID_KEY_1, CEC_KEYCODE_SELECT_BROADCAST_TYPE,
+ * UI_BROADCAST_TOGGLE_ALL);
+ * new KeycodeEntry(CUSTOME_ANDORID_KEY_2, CEC_KEYCODE_SELECT_BROADCAST_TYPE,
+ * UI_BROADCAST_ANALOGUE);
+ * </pre>
+ */
+ private static class KeycodeEntry {
+ private final int mAndroidKeycode;
+ private final int mCecKeycode;
+ private final int mParam;
+
+ private KeycodeEntry(int androidKeycode, int cecKeycode, int param) {
+ this.mAndroidKeycode = androidKeycode;
+ this.mCecKeycode = cecKeycode;
+ this.mParam = param;
+ }
+
+ private KeycodeEntry(int androidKeycode, int cecKeycode) {
+ this(androidKeycode, cecKeycode, NO_PARAM);
+ }
+
+ private byte[] toCecKeycodeIfMatched(int androidKeycode) {
+ if (mAndroidKeycode == androidKeycode) {
+ if (mParam == NO_PARAM) {
+ return new byte[] {
+ (byte) (mCecKeycode & 0xFF)
+ };
+ } else {
+ return new byte[] {
+ (byte) (mCecKeycode & 0xFF),
+ (byte) (mParam & 0xFF)
+ };
+ }
+ } else {
+ return null;
+ }
+ }
+
+ private int toAndroidKeycodeIfMatched(int cecKeycode, int param) {
+ if (cecKeycode == mCecKeycode && mParam == param) {
+ return mAndroidKeycode;
+ } else {
+ return UNSUPPORTED_KEYCODE;
+ }
+ }
+ }
+
+ // Keycode entry container for all mappings.
+ // Note that order of entry is the same as above cec keycode definition.
+ private static final KeycodeEntry[] KEYCODE_ENTRIES = new KeycodeEntry[] {
+ new KeycodeEntry(KeyEvent.KEYCODE_DPAD_CENTER, CEC_KEYCODE_SELECT),
+ new KeycodeEntry(KeyEvent.KEYCODE_DPAD_UP, CEC_KEYCODE_UP),
+ new KeycodeEntry(KeyEvent.KEYCODE_DPAD_DOWN, CEC_KEYCODE_DOWN),
+ new KeycodeEntry(KeyEvent.KEYCODE_DPAD_LEFT, CEC_KEYCODE_LEFT),
+ new KeycodeEntry(KeyEvent.KEYCODE_DPAD_RIGHT, CEC_KEYCODE_RIGHT),
+ // No Android keycode defined for CEC_KEYCODE_RIGHT_UP
+ // No Android keycode defined for CEC_KEYCODE_RIGHT_DOWN
+ // No Android keycode defined for CEC_KEYCODE_LEFT_UP
+ // No Android keycode defined for CEC_KEYCODE_LEFT_DOWN
+ new KeycodeEntry(KeyEvent.KEYCODE_HOME, CEC_KEYCODE_ROOT_MENU),
+ new KeycodeEntry(KeyEvent.KEYCODE_SETTINGS, CEC_KEYCODE_SETUP_MENU),
+ new KeycodeEntry(KeyEvent.KEYCODE_MENU, CEC_KEYCODE_CONTENTS_MENU),
+ // No Android keycode defined for CEC_KEYCODE_FAVORITE_MENU
+ new KeycodeEntry(KeyEvent.KEYCODE_BACK, CEC_KEYCODE_EXIT),
+ // RESERVED
+ new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_TOP_MENU, CEC_KEYCODE_MEDIA_TOP_MENU),
+ // No Android keycode defined for CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU
+ // RESERVED
+ // No Android keycode defined for CEC_KEYCODE_NUMBER_ENTRY_MODE
+ new KeycodeEntry(KeyEvent.KEYCODE_11, CEC_KEYCODE_NUMBER_11),
+ new KeycodeEntry(KeyEvent.KEYCODE_12, CEC_KEYCODE_NUMBER_12),
+ new KeycodeEntry(KeyEvent.KEYCODE_0, CEC_KEYCODE_NUMBER_0_OR_NUMBER_10),
+ new KeycodeEntry(KeyEvent.KEYCODE_1, CEC_KEYCODE_NUMBERS_1),
+ new KeycodeEntry(KeyEvent.KEYCODE_2, CEC_KEYCODE_NUMBERS_2),
+ new KeycodeEntry(KeyEvent.KEYCODE_3, CEC_KEYCODE_NUMBERS_3),
+ new KeycodeEntry(KeyEvent.KEYCODE_4, CEC_KEYCODE_NUMBERS_4),
+ new KeycodeEntry(KeyEvent.KEYCODE_5, CEC_KEYCODE_NUMBERS_5),
+ new KeycodeEntry(KeyEvent.KEYCODE_6, CEC_KEYCODE_NUMBERS_6),
+ new KeycodeEntry(KeyEvent.KEYCODE_7, CEC_KEYCODE_NUMBERS_7),
+ new KeycodeEntry(KeyEvent.KEYCODE_8, CEC_KEYCODE_NUMBERS_8),
+ new KeycodeEntry(KeyEvent.KEYCODE_9, CEC_KEYCODE_NUMBERS_9),
+ new KeycodeEntry(KeyEvent.KEYCODE_PERIOD, CEC_KEYCODE_DOT),
+ new KeycodeEntry(KeyEvent.KEYCODE_NUMPAD_ENTER, CEC_KEYCODE_ENTER),
+ new KeycodeEntry(KeyEvent.KEYCODE_CLEAR, CEC_KEYCODE_CLEAR),
+ // RESERVED
+ // No Android keycode defined for CEC_KEYCODE_NEXT_FAVORITE
+ new KeycodeEntry(KeyEvent.KEYCODE_CHANNEL_UP, CEC_KEYCODE_CHANNEL_UP),
+ new KeycodeEntry(KeyEvent.KEYCODE_CHANNEL_DOWN, CEC_KEYCODE_CHANNEL_DOWN),
+ new KeycodeEntry(KeyEvent.KEYCODE_LAST_CHANNEL, CEC_KEYCODE_PREVIOUS_CHANNEL),
+ // No Android keycode defined for CEC_KEYCODE_SOUND_SELECT
+ new KeycodeEntry(KeyEvent.KEYCODE_TV_INPUT, CEC_KEYCODE_INPUT_SELECT),
+ new KeycodeEntry(KeyEvent.KEYCODE_INFO, CEC_KEYCODE_DISPLAY_INFORMATION),
+ // No Android keycode defined for CEC_KEYCODE_HELP
+ new KeycodeEntry(KeyEvent.KEYCODE_PAGE_UP, CEC_KEYCODE_PAGE_UP),
+ new KeycodeEntry(KeyEvent.KEYCODE_PAGE_DOWN, CEC_KEYCODE_PAGE_DOWN),
+ // RESERVED
+ new KeycodeEntry(KeyEvent.KEYCODE_POWER, CEC_KEYCODE_POWER),
+ new KeycodeEntry(KeyEvent.KEYCODE_VOLUME_UP, CEC_KEYCODE_VOLUME_UP),
+ new KeycodeEntry(KeyEvent.KEYCODE_VOLUME_DOWN, CEC_KEYCODE_VOLUME_DOWN),
+ new KeycodeEntry(KeyEvent.KEYCODE_VOLUME_MUTE, CEC_KEYCODE_MUTE),
+ new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_PLAY, CEC_KEYCODE_PLAY),
+ new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_STOP, CEC_KEYCODE_STOP),
+ new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_PAUSE, CEC_KEYCODE_PAUSE),
+ new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_RECORD, CEC_KEYCODE_RECORD),
+ new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_REWIND, CEC_KEYCODE_REWIND),
+ new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, CEC_KEYCODE_FAST_FORWARD),
+ new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_EJECT, CEC_KEYCODE_EJECT),
+ new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_NEXT, CEC_KEYCODE_FORWARD),
+ new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_PREVIOUS, CEC_KEYCODE_BACKWARD),
+ // No Android keycode defined for CEC_KEYCODE_STOP_RECORD
+ // No Android keycode defined for CEC_KEYCODE_PAUSE_RECORD
+ // No Android keycode defined for CEC_KEYCODE_RESERVED
+ // No Android keycode defined for CEC_KEYCODE_ANGLE
+ // No Android keycode defined for CEC_KEYCODE_SUB_PICTURE
+ // No Android keycode defined for CEC_KEYCODE_VIDEO_ON_DEMAND
+ new KeycodeEntry(KeyEvent.KEYCODE_GUIDE, CEC_KEYCODE_ELECTRONIC_PROGRAM_GUIDE),
+ // No Android keycode defined for CEC_KEYCODE_TIMER_PROGRAMMING
+ // No Android keycode defined for CEC_KEYCODE_INITIAL_CONFIGURATION
+ // No Android keycode defined for CEC_KEYCODE_SELECT_BROADCAST_TYPE
+ // No Android keycode defined for CEC_KEYCODE_SELECT_SOUND_PRESENTATION
+ // RESERVED
+ // The following deterministic key definitions do not need key mapping
+ // since they are supposed to be generated programmatically only.
+ // No Android keycode defined for CEC_KEYCODE_PLAY_FUNCTION
+ // No Android keycode defined for CEC_KEYCODE_PAUSE_PLAY_FUNCTION
+ // No Android keycode defined for CEC_KEYCODE_RECORD_FUNCTION
+ // No Android keycode defined for CEC_KEYCODE_PAUSE_RECORD_FUNCTION
+ // No Android keycode defined for CEC_KEYCODE_STOP_FUNCTION
+ // No Android keycode defined for CEC_KEYCODE_MUTE_FUNCTION
+ // No Android keycode defined for CEC_KEYCODE_RESTORE_VOLUME_FUNCTION
+ // No Android keycode defined for CEC_KEYCODE_TUNE_FUNCTION
+ // No Android keycode defined for CEC_KEYCODE_SELECT_MEDIA_FUNCTION
+ // No Android keycode defined for CEC_KEYCODE_SELECT_AV_INPUT_FUNCTION
+ // No Android keycode defined for CEC_KEYCODE_SELECT_AUDIO_INPUT_FUNCTION
+ // No Android keycode defined for CEC_KEYCODE_POWER_TOGGLE_FUNCTION
+ // No Android keycode defined for CEC_KEYCODE_POWER_OFF_FUNCTION
+ // No Android keycode defined for CEC_KEYCODE_POWER_ON_FUNCTION
+ // RESERVED
+ new KeycodeEntry(KeyEvent.KEYCODE_PROG_BLUE, CEC_KEYCODE_F1_BLUE),
+ new KeycodeEntry(KeyEvent.KEYCODE_PROG_RED, CEC_KEYCODE_F2_RED),
+ new KeycodeEntry(KeyEvent.KEYCODE_PROG_GREEN, CEC_KEYCODE_F3_GREEN),
+ new KeycodeEntry(KeyEvent.KEYCODE_PROG_YELLOW, CEC_KEYCODE_F4_YELLOW),
+ new KeycodeEntry(KeyEvent.KEYCODE_F5, CEC_KEYCODE_F5),
+ new KeycodeEntry(KeyEvent.KEYCODE_TV_DATA_SERVICE, CEC_KEYCODE_DATA),
+ // RESERVED
+ // Add a new key mapping here if new keycode is introduced.
+ };
+
+ /**
+ * Translate Android keycode to Hdmi Cec keycode.
+ *
+ * @param keycode Android keycode. For details, refer {@link KeyEvent}
+ * @return array of byte which contains cec keycode and param if it has;
+ * return null if failed to find matched cec keycode
+ */
+ static byte[] androidKeyToCecKey(int keycode) {
+ for (int i = 0; i < KEYCODE_ENTRIES.length; ++i) {
+ byte[] cecKeycode = KEYCODE_ENTRIES[i].toCecKeycodeIfMatched(keycode);
+ if (cecKeycode != null) {
+ return cecKeycode;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Translate Hdmi CEC keycode to Android keycode.
+ *
+ * @param keycode Cec keycode. If has no param, put {@link #NO_PARAM}
+ * @return cec keycode corresponding to the given android keycode.
+ * If finds no matched keycode, return {@link #UNSUPPORTED_KEYCODE}
+ */
+ static int cecKeyToAndroidKey(int keycode, int param) {
+ for (int i = 0; i < KEYCODE_ENTRIES.length; ++i) {
+ int androidKey = KEYCODE_ENTRIES[i].toAndroidKeycodeIfMatched(keycode, param);
+ if (androidKey != UNSUPPORTED_KEYCODE) {
+ return androidKey;
+ }
+ }
+ return UNSUPPORTED_KEYCODE;
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 23454ad..08d7786 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -18,12 +18,23 @@
import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.os.Looper;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
/**
* Class that models a logical CEC device hosted in this system. Handles initialization,
* CEC commands that call for actions customized per device type.
*/
abstract class HdmiCecLocalDevice {
+ private static final String TAG = "HdmiCecLocalDevice";
protected final HdmiControlService mService;
protected final int mDeviceType;
@@ -31,10 +42,37 @@
protected int mPreferredAddress;
protected HdmiCecDeviceInfo mDeviceInfo;
+ // Logical address of the active source.
+ @GuardedBy("mLock")
+ private int mActiveSource;
+
+ // Active routing path. Physical address of the active source but not all the time, such as
+ // when the new active source does not claim itself to be one. Note that we don't keep
+ // the active port id (or active input) since it can be gotten by {@link #pathToPortId(int)}.
+ @GuardedBy("mLock")
+ private int mActiveRoutingPath;
+
+ // Set to true while the service is in normal mode. While set to false, no input change is
+ // allowed. Used for situations where input change can confuse users such as channel auto-scan,
+ // system upgrade, etc., a.k.a. "prohibit mode".
+ @GuardedBy("mLock")
+ private boolean mInputChangeEnabled;
+
+ protected final HdmiCecMessageCache mCecMessageCache = new HdmiCecMessageCache();
+ protected final Object mLock;
+
+ // A collection of FeatureAction.
+ // Note that access to this collection should happen in service thread.
+ private final LinkedList<FeatureAction> mActions = new LinkedList<>();
+
protected HdmiCecLocalDevice(HdmiControlService service, int deviceType) {
mService = service;
mDeviceType = deviceType;
mAddress = HdmiCec.ADDR_UNREGISTERED;
+ mLock = service.getServiceLock();
+
+ // TODO: Get control flag from persistent storage
+ mInputChangeEnabled = true;
}
// Factory method that returns HdmiCecLocalDevice of corresponding type.
@@ -59,34 +97,345 @@
*/
protected abstract void onAddressAllocated(int logicalAddress);
+ /**
+ * Dispatch incoming message.
+ *
+ * @param message incoming message
+ * @return true if consumed a message; otherwise, return false.
+ */
+ final boolean dispatchMessage(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+
+ int dest = message.getDestination();
+ if (dest != mAddress && dest != HdmiCec.ADDR_BROADCAST) {
+ return false;
+ }
+ // Cache incoming message. Note that it caches only white-listed one.
+ mCecMessageCache.cacheMessage(message);
+ return onMessage(message);
+ }
+
+ protected final boolean onMessage(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+
+ if (dispatchMessageToAction(message)) {
+ return true;
+ }
+ switch (message.getOpcode()) {
+ case HdmiCec.MESSAGE_GET_MENU_LANGUAGE:
+ return handleGetMenuLanguage(message);
+ case HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS:
+ return handleGivePhysicalAddress();
+ case HdmiCec.MESSAGE_GIVE_OSD_NAME:
+ return handleGiveOsdName(message);
+ case HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID:
+ return handleGiveDeviceVendorId();
+ case HdmiCec.MESSAGE_GET_CEC_VERSION:
+ return handleGetCecVersion(message);
+ case HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS:
+ return handleReportPhysicalAddress(message);
+ case HdmiCec.MESSAGE_INITIATE_ARC:
+ return handleInitiateArc(message);
+ case HdmiCec.MESSAGE_TERMINATE_ARC:
+ return handleTerminateArc(message);
+ case HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE:
+ return handleSetSystemAudioMode(message);
+ case HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
+ return handleSystemAudioModeStatus(message);
+ default:
+ return false;
+ }
+ }
+
+ private boolean dispatchMessageToAction(HdmiCecMessage message) {
+ for (FeatureAction action : mActions) {
+ if (action.processCommand(message)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected boolean handleGivePhysicalAddress() {
+ assertRunOnServiceThread();
+
+ int physicalAddress = mService.getPhysicalAddress();
+ HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ mAddress, physicalAddress, mDeviceType);
+ mService.sendCecCommand(cecMessage);
+ return true;
+ }
+
+ protected boolean handleGiveDeviceVendorId() {
+ assertRunOnServiceThread();
+
+ int vendorId = mService.getVendorId();
+ HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
+ mAddress, vendorId);
+ mService.sendCecCommand(cecMessage);
+ return true;
+ }
+
+ protected boolean handleGetCecVersion(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+
+ int version = mService.getCecVersion();
+ HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(),
+ message.getSource(), version);
+ mService.sendCecCommand(cecMessage);
+ return true;
+ }
+
+ protected boolean handleGetMenuLanguage(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+
+ Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString());
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
+ message.getSource(), HdmiCec.MESSAGE_GET_MENU_LANGUAGE,
+ HdmiConstants.ABORT_UNRECOGNIZED_MODE));
+ return true;
+ }
+
+ protected boolean handleGiveOsdName(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+
+ // Note that since this method is called after logical address allocation is done,
+ // mDeviceInfo should not be null.
+ HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand(
+ mAddress, message.getSource(), mDeviceInfo.getDisplayName());
+ if (cecMessage != null) {
+ mService.sendCecCommand(cecMessage);
+ } else {
+ Slog.w(TAG, "Failed to build <Get Osd Name>:" + mDeviceInfo.getDisplayName());
+ }
+ return true;
+ }
+
+ protected boolean handleVendorSpecificCommand(HdmiCecMessage message) {
+ return false;
+ }
+
+ protected boolean handleReportPhysicalAddress(HdmiCecMessage message) {
+ return false;
+ }
+
+ protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) {
+ return false;
+ }
+
+ protected boolean handleSetSystemAudioMode(HdmiCecMessage message) {
+ return false;
+ }
+
+ protected boolean handleTerminateArc(HdmiCecMessage message) {
+ return false;
+ }
+
+ protected boolean handleInitiateArc(HdmiCecMessage message) {
+ return false;
+ }
+
final void handleAddressAllocated(int logicalAddress) {
+ assertRunOnServiceThread();
+
mAddress = mPreferredAddress = logicalAddress;
onAddressAllocated(logicalAddress);
}
HdmiCecDeviceInfo getDeviceInfo() {
+ assertRunOnServiceThread();
return mDeviceInfo;
}
void setDeviceInfo(HdmiCecDeviceInfo info) {
+ assertRunOnServiceThread();
mDeviceInfo = info;
}
// Returns true if the logical address is same as the argument.
boolean isAddressOf(int addr) {
+ assertRunOnServiceThread();
return addr == mAddress;
}
// Resets the logical address to unregistered(15), meaning the logical device is invalid.
void clearAddress() {
+ assertRunOnServiceThread();
mAddress = HdmiCec.ADDR_UNREGISTERED;
}
void setPreferredAddress(int addr) {
+ assertRunOnServiceThread();
mPreferredAddress = addr;
}
int getPreferredAddress() {
+ assertRunOnServiceThread();
return mPreferredAddress;
}
+
+ void addAndStartAction(final FeatureAction action) {
+ assertRunOnServiceThread();
+ mActions.add(action);
+ action.start();
+ }
+
+ // See if we have an action of a given type in progress.
+ <T extends FeatureAction> boolean hasAction(final Class<T> clazz) {
+ assertRunOnServiceThread();
+ for (FeatureAction action : mActions) {
+ if (action.getClass().equals(clazz)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Returns all actions matched with given class type.
+ <T extends FeatureAction> List<T> getActions(final Class<T> clazz) {
+ assertRunOnServiceThread();
+ ArrayList<T> actions = new ArrayList<>();
+ for (FeatureAction action : mActions) {
+ if (action.getClass().equals(clazz)) {
+ actions.add((T) action);
+ }
+ }
+ return actions;
+ }
+
+ /**
+ * Remove the given {@link FeatureAction} object from the action queue.
+ *
+ * @param action {@link FeatureAction} to remove
+ */
+ void removeAction(final FeatureAction action) {
+ assertRunOnServiceThread();
+ mActions.remove(action);
+ }
+
+ // Remove all actions matched with the given Class type.
+ <T extends FeatureAction> void removeAction(final Class<T> clazz) {
+ removeActionExcept(clazz, null);
+ }
+
+ // Remove all actions matched with the given Class type besides |exception|.
+ <T extends FeatureAction> void removeActionExcept(final Class<T> clazz,
+ final FeatureAction exception) {
+ assertRunOnServiceThread();
+ Iterator<FeatureAction> iter = mActions.iterator();
+ while (iter.hasNext()) {
+ FeatureAction action = iter.next();
+ if (action != exception && action.getClass().equals(clazz)) {
+ action.clear();
+ mActions.remove(action);
+ }
+ }
+ }
+
+ protected void assertRunOnServiceThread() {
+ if (Looper.myLooper() != mService.getServiceLooper()) {
+ throw new IllegalStateException("Should run on service thread.");
+ }
+ }
+
+ /**
+ * Called when a hot-plug event issued.
+ *
+ * @param portId id of port where a hot-plug event happened
+ * @param connected whether to connected or not on the event
+ */
+ void onHotplug(int portId, boolean connected) {
+ }
+
+ final HdmiControlService getService() {
+ return mService;
+ }
+
+ final boolean isConnectedToArcPort(int path) {
+ return mService.isConnectedToArcPort(path);
+ }
+
+ int getActiveSource() {
+ synchronized (mLock) {
+ return mActiveSource;
+ }
+ }
+
+ /**
+ * Returns the active routing path.
+ */
+ int getActivePath() {
+ synchronized (mLock) {
+ return mActiveRoutingPath;
+ }
+ }
+
+ /**
+ * Returns the ID of the active HDMI port. The active input is the port that has the active
+ * routing path connected directly or indirectly under the device hierarchy.
+ */
+ int getActiveInput() {
+ synchronized (mLock) {
+ return mService.pathToPortId(mActiveRoutingPath);
+ }
+ }
+
+ void updateActiveDevice(int logicalAddress, int physicalAddress) {
+ synchronized (mLock) {
+ mActiveSource = logicalAddress;
+ mActiveRoutingPath = physicalAddress;
+ }
+ }
+
+ void setInputChangeEnabled(boolean enabled) {
+ synchronized (mLock) {
+ mInputChangeEnabled = enabled;
+ }
+ }
+
+ boolean isInPresetInstallationMode() {
+ synchronized (mLock) {
+ return !mInputChangeEnabled;
+ }
+ }
+
+ /**
+ * Whether the given path is located in the tail of current active path.
+ *
+ * @param path to be tested
+ * @return true if the given path is located in the tail of current active path; otherwise,
+ * false
+ */
+ // TODO: move this to local device tv.
+ boolean isTailOfActivePath(int path) {
+ synchronized (mLock) {
+ // If active routing path is internal source, return false.
+ if (mActiveRoutingPath == 0) {
+ return false;
+ }
+ for (int i = 12; i >= 0; i -= 4) {
+ int curActivePath = (mActiveRoutingPath >> i) & 0xF;
+ if (curActivePath == 0) {
+ return true;
+ } else {
+ int curPath = (path >> i) & 0xF;
+ if (curPath != curActivePath) {
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+ }
+
+ HdmiCecMessageCache getCecMessageCache() {
+ assertRunOnServiceThread();
+ return mCecMessageCache;
+ }
+
+ int pathToPortId(int newPath) {
+ assertRunOnServiceThread();
+ return mService.pathToPortId(newPath);
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index d79e283..01345ef 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -17,11 +17,15 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.RemoteException;
+import android.util.Slog;
/**
* Represent a logical device of type Playback residing in Android system.
*/
final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
+ private static final String TAG = "HdmiCecLocalDevicePlayback";
HdmiCecLocalDevicePlayback(HdmiControlService service) {
super(service, HdmiCec.DEVICE_PLAYBACK);
@@ -32,4 +36,54 @@
mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
mAddress, mService.getPhysicalAddress(), mDeviceType));
}
+
+ void oneTouchPlay(IHdmiControlCallback callback) {
+ assertRunOnServiceThread();
+ if (hasAction(OneTouchPlayAction.class)) {
+ Slog.w(TAG, "oneTouchPlay already in progress");
+ invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS);
+ return;
+ }
+
+ // TODO: Consider the case of multiple TV sets. For now we always direct the command
+ // to the primary one.
+ OneTouchPlayAction action = OneTouchPlayAction.create(this, HdmiCec.ADDR_TV, callback);
+ if (action == null) {
+ Slog.w(TAG, "Cannot initiate oneTouchPlay");
+ invokeCallback(callback, HdmiCec.RESULT_EXCEPTION);
+ return;
+ }
+ addAndStartAction(action);
+ }
+
+ void queryDisplayStatus(IHdmiControlCallback callback) {
+ assertRunOnServiceThread();
+ if (hasAction(DevicePowerStatusAction.class)) {
+ Slog.w(TAG, "queryDisplayStatus already in progress");
+ invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS);
+ return;
+ }
+ DevicePowerStatusAction action = DevicePowerStatusAction.create(this,
+ HdmiCec.ADDR_TV, callback);
+ if (action == null) {
+ Slog.w(TAG, "Cannot initiate queryDisplayStatus");
+ invokeCallback(callback, HdmiCec.RESULT_EXCEPTION);
+ return;
+ }
+ addAndStartAction(action);
+ }
+
+ private void invokeCallback(IHdmiControlCallback callback, int result) {
+ try {
+ callback.onComplete(result);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Invoking callback failed:" + e);
+ }
+ }
+
+ @Override
+ void onHotplug(int portId, boolean connected) {
+ // TODO: clear devices connected to the given port id.
+ mCecMessageCache.flushAll();
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 72d7f2d..92ddd3d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -17,11 +17,38 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
/**
* Represent a logical device of type TV residing in Android system.
*/
final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
+ private static final String TAG = "HdmiCecLocalDeviceTv";
+
+ // Whether ARC is "enabled" or not.
+ @GuardedBy("mLock")
+ private boolean mArcStatusEnabled = false;
+
+ @GuardedBy("mLock")
+ // Whether SystemAudioMode is "On" or not.
+ private boolean mSystemAudioMode;
+
+ // Map-like container of all cec devices including local ones.
+ // A logical address of device is used as key of container.
+ private final SparseArray<HdmiCecDeviceInfo> mDeviceInfos = new SparseArray<>();
HdmiCecLocalDeviceTv(HdmiControlService service) {
super(service, HdmiCec.DEVICE_TV);
@@ -29,6 +56,7 @@
@Override
protected void onAddressAllocated(int logicalAddress) {
+ assertRunOnServiceThread();
// TODO: vendor-specific initialization here.
mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
@@ -36,7 +64,396 @@
mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
mAddress, mService.getVendorId()));
- mService.launchDeviceDiscovery(mAddress);
+ launchDeviceDiscovery();
// TODO: Start routing control action, device discovery action.
}
+
+ /**
+ * Performs the action 'device select', or 'one touch play' initiated by TV.
+ *
+ * @param targetAddress logical address of the device to select
+ * @param callback callback object to report the result with
+ */
+ void deviceSelect(int targetAddress, IHdmiControlCallback callback) {
+ assertRunOnServiceThread();
+ HdmiCecDeviceInfo targetDevice = mService.getDeviceInfo(targetAddress);
+ if (targetDevice == null) {
+ invokeCallback(callback, HdmiCec.RESULT_TARGET_NOT_AVAILABLE);
+ return;
+ }
+ removeAction(DeviceSelectAction.class);
+ addAndStartAction(new DeviceSelectAction(this, targetDevice, callback));
+ }
+
+ private static void invokeCallback(IHdmiControlCallback callback, int result) {
+ try {
+ callback.onComplete(result);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Invoking callback failed:" + e);
+ }
+ }
+
+ @Override
+ protected boolean handleGetMenuLanguage(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand(
+ mAddress, Locale.getDefault().getISO3Language());
+ // TODO: figure out how to handle failed to get language code.
+ if (command != null) {
+ mService.sendCecCommand(command);
+ } else {
+ Slog.w(TAG, "Failed to respond to <Get Menu Language>: " + message.toString());
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean handleReportPhysicalAddress(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ // Ignore if [Device Discovery Action] is going on.
+ if (hasAction(DeviceDiscoveryAction.class)) {
+ Slog.i(TAG, "Ignore unrecognizable <Report Physical Address> "
+ + "because Device Discovery Action is on-going:" + message);
+ return true;
+ }
+
+ int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+ int logicalAddress = message.getSource();
+
+ // If it is a new device and connected to the tail of active path,
+ // it's required to change routing path.
+ boolean requireRoutingChange = !isInDeviceList(physicalAddress, logicalAddress)
+ && isTailOfActivePath(physicalAddress);
+ addAndStartAction(new NewDeviceAction(this, message.getSource(), physicalAddress,
+ requireRoutingChange));
+ return true;
+ }
+
+ @Override
+ protected boolean handleVendorSpecificCommand(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ List<VendorSpecificAction> actions = Collections.emptyList();
+ // TODO: Call mService.getActions(VendorSpecificAction.class) to get all the actions.
+
+ // We assume that there can be multiple vendor-specific command actions running
+ // at the same time. Pass the message to each action to see if one of them needs it.
+ for (VendorSpecificAction action : actions) {
+ if (action.processCommand(message)) {
+ return true;
+ }
+ }
+ // Handle the message here if it is not already consumed by one of the running actions.
+ // Respond with a appropriate vendor-specific command or <Feature Abort>, or create another
+ // vendor-specific action:
+ //
+ // mService.addAndStartAction(new VendorSpecificAction(mService, mAddress));
+ //
+ // For now, simply reply with <Feature Abort> and mark it consumed by returning true.
+ mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(
+ message.getDestination(), message.getSource(), message.getOpcode(),
+ HdmiConstants.ABORT_REFUSED));
+ return true;
+ }
+
+ private void launchDeviceDiscovery() {
+ assertRunOnServiceThread();
+ clearDeviceInfoList();
+ DeviceDiscoveryAction action = new DeviceDiscoveryAction(this,
+ new DeviceDiscoveryCallback() {
+ @Override
+ public void onDeviceDiscoveryDone(List<HdmiCecDeviceInfo> deviceInfos) {
+ for (HdmiCecDeviceInfo info : deviceInfos) {
+ addCecDevice(info);
+ }
+
+ // Since we removed all devices when it's start and
+ // device discovery action does not poll local devices,
+ // we should put device info of local device manually here
+ for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) {
+ addCecDevice(device.getDeviceInfo());
+ }
+
+ addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this));
+ }
+ });
+ addAndStartAction(action);
+ }
+
+ // Clear all device info.
+ private void clearDeviceInfoList() {
+ assertRunOnServiceThread();
+ mDeviceInfos.clear();
+ }
+
+ void setSystemAudioMode(boolean on) {
+ synchronized (mLock) {
+ if (on != mSystemAudioMode) {
+ mSystemAudioMode = on;
+ // TODO: Need to set the preference for SystemAudioMode.
+ // TODO: Need to handle the notification of changing the mode and
+ // to identify the notification should be handled in the service or TvSettings.
+ }
+ }
+ }
+
+ boolean getSystemAudioMode() {
+ synchronized (mLock) {
+ assertRunOnServiceThread();
+ return mSystemAudioMode;
+ }
+ }
+
+ /**
+ * Change ARC status into the given {@code enabled} status.
+ *
+ * @return {@code true} if ARC was in "Enabled" status
+ */
+ boolean setArcStatus(boolean enabled) {
+ synchronized (mLock) {
+ boolean oldStatus = mArcStatusEnabled;
+ // 1. Enable/disable ARC circuit.
+ mService.setAudioReturnChannel(enabled);
+
+ // TODO: notify arc mode change to AudioManager.
+
+ // 2. Update arc status;
+ mArcStatusEnabled = enabled;
+ return oldStatus;
+ }
+ }
+
+ /**
+ * Returns whether ARC is enabled or not.
+ */
+ boolean getArcStatus() {
+ synchronized (mLock) {
+ return mArcStatusEnabled;
+ }
+ }
+
+ void setAudioStatus(boolean mute, int volume) {
+ mService.setAudioStatus(mute, volume);
+ }
+
+ @Override
+ protected boolean handleInitiateArc(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ // In case where <Initiate Arc> is started by <Request ARC Initiation>
+ // need to clean up RequestArcInitiationAction.
+ removeAction(RequestArcInitiationAction.class);
+ SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this,
+ message.getSource(), true);
+ addAndStartAction(action);
+ return true;
+ }
+
+ @Override
+ protected boolean handleTerminateArc(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ // In case where <Terminate Arc> is started by <Request ARC Termination>
+ // need to clean up RequestArcInitiationAction.
+ // TODO: check conditions of power status by calling is_connected api
+ // to be added soon.
+ removeAction(RequestArcTerminationAction.class);
+ SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this,
+ message.getSource(), false);
+ addAndStartAction(action);
+ return true;
+ }
+
+ @Override
+ protected boolean handleSetSystemAudioMode(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ if (!isMessageForSystemAudio(message)) {
+ return false;
+ }
+ SystemAudioActionFromAvr action = new SystemAudioActionFromAvr(this,
+ message.getSource(), HdmiUtils.parseCommandParamSystemAudioStatus(message));
+ addAndStartAction(action);
+ return true;
+ }
+
+ @Override
+ protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ if (!isMessageForSystemAudio(message)) {
+ return false;
+ }
+ setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message));
+ return true;
+ }
+
+ private boolean isMessageForSystemAudio(HdmiCecMessage message) {
+ if (message.getSource() != HdmiCec.ADDR_AUDIO_SYSTEM
+ || message.getDestination() != HdmiCec.ADDR_TV
+ || getAvrDeviceInfo() == null) {
+ Slog.w(TAG, "Skip abnormal CecMessage: " + message);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Add a new {@link HdmiCecDeviceInfo}. It returns old device info which has the same
+ * logical address as new device info's.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ *
+ * @param deviceInfo a new {@link HdmiCecDeviceInfo} to be added.
+ * @return {@code null} if it is new device. Otherwise, returns old {@HdmiCecDeviceInfo}
+ * that has the same logical address as new one has.
+ */
+ HdmiCecDeviceInfo addDeviceInfo(HdmiCecDeviceInfo deviceInfo) {
+ assertRunOnServiceThread();
+ HdmiCecDeviceInfo oldDeviceInfo = getDeviceInfo(deviceInfo.getLogicalAddress());
+ if (oldDeviceInfo != null) {
+ removeDeviceInfo(deviceInfo.getLogicalAddress());
+ }
+ mDeviceInfos.append(deviceInfo.getLogicalAddress(), deviceInfo);
+ return oldDeviceInfo;
+ }
+
+ /**
+ * Remove a device info corresponding to the given {@code logicalAddress}.
+ * It returns removed {@link HdmiCecDeviceInfo} if exists.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ *
+ * @param logicalAddress logical address of device to be removed
+ * @return removed {@link HdmiCecDeviceInfo} it exists. Otherwise, returns {@code null}
+ */
+ HdmiCecDeviceInfo removeDeviceInfo(int logicalAddress) {
+ assertRunOnServiceThread();
+ HdmiCecDeviceInfo deviceInfo = mDeviceInfos.get(logicalAddress);
+ if (deviceInfo != null) {
+ mDeviceInfos.remove(logicalAddress);
+ }
+ return deviceInfo;
+ }
+
+ /**
+ * Return a list of all {@link HdmiCecDeviceInfo}.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ */
+ List<HdmiCecDeviceInfo> getDeviceInfoList(boolean includelLocalDevice) {
+ assertRunOnServiceThread();
+ if (includelLocalDevice) {
+ return HdmiUtils.sparseArrayToList(mDeviceInfos);
+ } else {
+
+ ArrayList<HdmiCecDeviceInfo> infoList = new ArrayList<>();
+ for (int i = 0; i < mDeviceInfos.size(); ++i) {
+ HdmiCecDeviceInfo info = mDeviceInfos.valueAt(i);
+ if (!isLocalDeviceAddress(info.getLogicalAddress())) {
+ infoList.add(info);
+ }
+ }
+ return infoList;
+ }
+ }
+
+ private boolean isLocalDeviceAddress(int address) {
+ assertRunOnServiceThread();
+ for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) {
+ if (device.isAddressOf(address)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return a {@link HdmiCecDeviceInfo} corresponding to the given {@code logicalAddress}.
+ *
+ * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
+ *
+ * @param logicalAddress logical address to be retrieved
+ * @return {@link HdmiCecDeviceInfo} matched with the given {@code logicalAddress}.
+ * Returns null if no logical address matched
+ */
+ HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) {
+ assertRunOnServiceThread();
+ return mDeviceInfos.get(logicalAddress);
+ }
+
+ HdmiCecDeviceInfo getAvrDeviceInfo() {
+ assertRunOnServiceThread();
+ return getDeviceInfo(HdmiCec.ADDR_AUDIO_SYSTEM);
+ }
+
+ /**
+ * Called when a device is newly added or a new device is detected.
+ *
+ * @param info device info of a new device.
+ */
+ final void addCecDevice(HdmiCecDeviceInfo info) {
+ assertRunOnServiceThread();
+ addDeviceInfo(info);
+
+ // TODO: announce new device detection.
+ }
+
+ /**
+ * Called when a device is removed or removal of device is detected.
+ *
+ * @param address a logical address of a device to be removed
+ */
+ final void removeCecDevice(int address) {
+ assertRunOnServiceThread();
+ removeDeviceInfo(address);
+ mCecMessageCache.flushMessagesFrom(address);
+
+ // TODO: announce a device removal.
+ }
+
+ /**
+ * Returns the {@link HdmiCecDeviceInfo} instance whose physical address matches
+ * the given routing path. CEC devices use routing path for its physical address to
+ * describe the hierarchy of the devices in the network.
+ *
+ * @param path routing path or physical address
+ * @return {@link HdmiCecDeviceInfo} if the matched info is found; otherwise null
+ */
+ final HdmiCecDeviceInfo getDeviceInfoByPath(int path) {
+ assertRunOnServiceThread();
+ for (HdmiCecDeviceInfo info : getDeviceInfoList(false)) {
+ if (info.getPhysicalAddress() == path) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Whether a device of the specified physical address and logical address exists
+ * in a device info list. However, both are minimal condition and it could
+ * be different device from the original one.
+ *
+ * @param physicalAddress physical address of a device to be searched
+ * @param logicalAddress logical address of a device to be searched
+ * @return true if exist; otherwise false
+ */
+ boolean isInDeviceList(int physicalAddress, int logicalAddress) {
+ assertRunOnServiceThread();
+ HdmiCecDeviceInfo device = getDeviceInfo(logicalAddress);
+ if (device == null) {
+ return false;
+ }
+ return device.getPhysicalAddress() == physicalAddress;
+ }
+
+ @Override
+ void onHotplug(int portNo, boolean connected) {
+ assertRunOnServiceThread();
+ // TODO: delegate onHotplug event to each local device.
+
+ // Tv device will have permanent HotplugDetectionAction.
+ List<HotplugDetectionAction> hotplugActions = getActions(HotplugDetectionAction.class);
+ if (!hotplugActions.isEmpty()) {
+ // Note that hotplug action is single action running on a machine.
+ // "pollAllDevicesNow" cleans up timer and start poll action immediately.
+ hotplugActions.get(0).pollAllDevicesNow();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 6c2be34..8dbfd85 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -270,6 +270,38 @@
}
/**
+ * Build <Set Stream Path> command.
+ *
+ * <p>This is a broadcast message sent to all devices on the bus.
+ *
+ * @param src source address of command
+ * @param streamPath physical address of the device to start streaming
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildSetStreamPath(int src, int streamPath) {
+ return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_SET_STREAM_PATH,
+ physicalAddressToParam(streamPath));
+ }
+
+ /**
+ * Build <Routing Change> command.
+ *
+ * <p>This is a broadcast message sent to all devices on the bus.
+ *
+ * @param src source address of command
+ * @param oldPath physical address of the currently active routing path
+ * @param newPath physical address of the new active routing path
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildRoutingChange(int src, int oldPath, int newPath) {
+ byte[] param = new byte[] {
+ (byte) ((oldPath >> 8) & 0xFF), (byte) (oldPath & 0xFF),
+ (byte) ((newPath >> 8) & 0xFF), (byte) (newPath & 0xFF)
+ };
+ return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_ROUTING_CHANGE, param);
+ }
+
+ /**
* Build <Give Device Power Status> command.
*
* @param src source address of command
@@ -319,10 +351,19 @@
* @return newly created {@link HdmiCecMessage}
*/
static HdmiCecMessage buildUserControlPressed(int src, int dest, int uiCommand) {
- byte[] params = new byte[] {
- (byte) uiCommand
- };
- return buildCommand(src, dest, HdmiCec.MESSAGE_USER_CONTROL_PRESSED, params);
+ return buildUserControlPressed(src, dest, new byte[] { (byte) uiCommand });
+ }
+
+ /**
+ * Build <User Control Pressed> command.
+ *
+ * @param src source address of command
+ * @param dest destination address of command
+ * @param commandParam uiCommand and the additional parameter
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildUserControlPressed(int src, int dest, byte[] commandParam) {
+ return buildCommand(src, dest, HdmiCec.MESSAGE_USER_CONTROL_PRESSED, commandParam);
}
/**
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageCache.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageCache.java
new file mode 100644
index 0000000..abda656
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageCache.java
@@ -0,0 +1,104 @@
+/*
+ * 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.server.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.util.FastImmutableArraySet;
+import android.util.SparseArray;
+
+/**
+ * Cache for incoming message. It caches {@link HdmiCecMessage} with source address and opcode
+ * as a key.
+ *
+ * <p>Note that whenever a device is removed it should call {@link #flushMessagesFrom(int)}
+ * to clean up messages come from the device.
+ */
+final class HdmiCecMessageCache {
+ private static final FastImmutableArraySet<Integer> CACHEABLE_OPCODES = new FastImmutableArraySet<>(
+ new Integer[] {
+ HdmiCec.MESSAGE_SET_OSD_NAME,
+ HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS,
+ HdmiCec.MESSAGE_DEVICE_VENDOR_ID,
+ HdmiCec.MESSAGE_CEC_VERSION,
+ });
+
+ // It's like [Source Logical Address, [Opcode, HdmiCecMessage]].
+ private final SparseArray<SparseArray<HdmiCecMessage>> mCache = new SparseArray<>();
+
+ HdmiCecMessageCache() {
+ }
+
+ /**
+ * Return a {@link HdmiCecMessage} corresponding to the given {@code address} and
+ * {@code opcode}.
+ *
+ * @param address a logical address of source device
+ * @param opcode opcode of message
+ * @return null if has no {@link HdmiCecMessage} matched to the given {@code address} and {code
+ * opcode}
+ */
+ public HdmiCecMessage getMessage(int address, int opcode) {
+ SparseArray<HdmiCecMessage> messages = mCache.get(address);
+ if (messages == null) {
+ return null;
+ }
+
+ return messages.get(opcode);
+ }
+
+ /**
+ * Flush all {@link HdmiCecMessage}s sent from the given {@code address}.
+ *
+ * @param address a logical address of source device
+ */
+ public void flushMessagesFrom(int address) {
+ mCache.remove(address);
+ }
+
+ /**
+ * Flush all cached {@link HdmiCecMessage}s.
+ */
+ public void flushAll() {
+ mCache.clear();
+ }
+
+ /**
+ * Cache incoming {@link HdmiCecMessage}. If opcode of message is not listed on
+ * cacheable opcodes list, just ignore it.
+ *
+ * @param message a {@link HdmiCecMessage} to be cached
+ */
+ public void cacheMessage(HdmiCecMessage message) {
+ int opcode = message.getOpcode();
+ if (!isCacheable(opcode)) {
+ return;
+ }
+
+ int source = message.getSource();
+ SparseArray<HdmiCecMessage> messages = mCache.get(source);
+ if (messages == null) {
+ messages = new SparseArray<>();
+ mCache.put(source, messages);
+ }
+ messages.put(opcode, message);
+ }
+
+ private boolean isCacheable(int opcode) {
+ return CACHEABLE_OPCODES.contains(opcode);
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecService.java b/services/core/java/com/android/server/hdmi/HdmiCecService.java
deleted file mode 100644
index 98dc72f..0000000
--- a/services/core/java/com/android/server/hdmi/HdmiCecService.java
+++ /dev/null
@@ -1,383 +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.server.hdmi;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.hardware.hdmi.HdmiCec;
-import android.hardware.hdmi.HdmiCecMessage;
-import android.hardware.hdmi.IHdmiCecListener;
-import android.hardware.hdmi.IHdmiCecService;
-import android.os.Binder;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.server.SystemService;
-import libcore.util.EmptyArray;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Locale;
-
-/**
- * Provides a service for sending and processing HDMI-CEC messages, and providing
- * the information on HDMI settings in general.
- */
-public final class HdmiCecService extends SystemService {
- private static final String TAG = "HdmiCecService";
-
- // Maintains the allocated logical devices. Device type, not logical address,
- // is used for key as logical address is likely to change over time while
- // device type is permanent. Type-address mapping is maintained only at
- // native level.
- private final SparseArray<HdmiCecDevice> mLogicalDevices = new SparseArray<HdmiCecDevice>();
-
- // List of IBinder.DeathRecipient instances to handle dead IHdmiCecListener
- // objects.
- private final ArrayList<ListenerRecord> mListenerRecords = new ArrayList<ListenerRecord>();
-
- // Used to synchronize the access to the service.
- private final Object mLock = new Object();
-
- // Stores the pointer to the native implementation of the service that
- // interacts with HAL.
- private long mNativePtr;
-
- private static final String PERMISSION = "android.permission.HDMI_CEC";
-
- static final byte[] EMPTY_PARAM = EmptyArray.BYTE;
-
- public HdmiCecService(Context context) {
- super(context);
- }
-
- private static native long nativeInit(HdmiCecService service);
-
- @Override
- public void onStart() {
- // Stop publishing the service. Soon to be deprecated.
- Log.w(TAG, "In transition to HdmiControlService. May not work.");
- }
-
- /**
- * Called by native when an HDMI-CEC message arrived. Invokes the registered
- * listeners to handle the message.
- */
- private void handleMessage(int srcAddress, int dstAddress, int opcode, byte[] params) {
- // TODO: Messages like <Standby> may not need be passed to listener
- // but better be handled in service by turning off the screen
- // or putting the device into suspend mode. List up such messages
- // and handle them here.
- synchronized (mLock) {
- if (dstAddress == HdmiCec.ADDR_BROADCAST) {
- for (int i = 0; i < mLogicalDevices.size(); ++i) {
- mLogicalDevices.valueAt(i).handleMessage(srcAddress, dstAddress, opcode,
- params);
- }
- } else {
- int type = HdmiCec.getTypeFromAddress(dstAddress);
- HdmiCecDevice device = mLogicalDevices.get(type);
- if (device == null) {
- Log.w(TAG, "logical device not found. type: " + type);
- return;
- }
- device.handleMessage(srcAddress, dstAddress, opcode, params);
- }
- }
- }
-
- /**
- * Called by native when internal HDMI hotplug event occurs. Invokes the registered
- * listeners to handle the event.
- */
- private void handleHotplug(boolean connected) {
- synchronized(mLock) {
- for (int i = 0; i < mLogicalDevices.size(); ++i) {
- mLogicalDevices.valueAt(i).handleHotplug(connected);
- }
- }
- }
-
- /**
- * Called by native when it needs to know whether we have an active source.
- * The native part uses the return value to respond to <Request Active
- * Source >.
- *
- * @return type of the device which is active; DEVICE_INACTIVE if there is
- * no active logical device in the system.
- */
- private int getActiveSource() {
- synchronized(mLock) {
- for (int i = 0; i < mLogicalDevices.size(); ++i) {
- if (mLogicalDevices.valueAt(i).isActiveSource()) {
- return mLogicalDevices.keyAt(i);
- }
- }
- }
- return HdmiCec.DEVICE_INACTIVE;
- }
-
- /**
- * Called by native when a request for the menu language of the device was
- * received. The native part uses the return value to generate the message
- * <Set Menu Language> in response. The language should be of
- * the 3-letter format as defined in ISO/FDIS 639-2. We use system default
- * locale.
- */
- private String getLanguage(int type) {
- return Locale.getDefault().getISO3Language();
- }
-
- private void enforceAccessPermission() {
- getContext().enforceCallingOrSelfPermission(PERMISSION, "HdmiCecService");
- }
-
- private void dumpInternal(PrintWriter pw) {
- pw.println("HdmiCecService (dumpsys hdmi_cec)");
- pw.println("");
- synchronized (mLock) {
- for (int i = 0; i < mLogicalDevices.size(); ++i) {
- HdmiCecDevice device = mLogicalDevices.valueAt(i);
- pw.println("Device: type=" + device.getType() +
- ", active=" + device.isActiveSource());
- }
- }
- }
-
- // Remove logical device of a given type.
- private void removeLogicalDeviceLocked(int type) {
- ensureValidType(type);
- mLogicalDevices.remove(type);
- nativeRemoveLogicalAddress(mNativePtr, type);
- }
-
- private static void ensureValidType(int type) {
- if (!HdmiCec.isValidType(type)) {
- throw new IllegalArgumentException("invalid type: " + type);
- }
- }
-
- // Return the logical device identified by the given binder token.
- private HdmiCecDevice getLogicalDeviceLocked(IBinder b) {
- for (int i = 0; i < mLogicalDevices.size(); ++i) {
- HdmiCecDevice device = mLogicalDevices.valueAt(i);
- if (device.getToken() == b) {
- return device;
- }
- }
- throw new IllegalArgumentException("Device not found");
- }
-
- // package-private. Used by HdmiCecDevice and its subclasses only.
- void sendMessage(int type, int address, int opcode, byte[] params) {
- nativeSendMessage(mNativePtr, type, address, opcode, params);
- }
-
- private void setOsdNameLocked(String name) {
- nativeSetOsdName(mNativePtr, name.getBytes(Charset.forName("US-ASCII")));
- }
-
- private final class ListenerRecord implements IBinder.DeathRecipient {
- private final IHdmiCecListener mListener;
- private final int mType;
-
- public ListenerRecord(IHdmiCecListener listener, int type) {
- mListener = listener;
- mType = type;
- }
-
- @Override
- public void binderDied() {
- synchronized (mLock) {
- mListenerRecords.remove(this);
- HdmiCecDevice device = mLogicalDevices.get(mType);
- if (device != null) {
- device.removeListener(mListener);
- if (!device.hasListener()) {
- removeLogicalDeviceLocked(mType);
- }
- }
- }
- }
- }
-
- private final class BinderService extends IHdmiCecService.Stub {
-
- @Override
- public IBinder allocateLogicalDevice(int type, IHdmiCecListener listener) {
- enforceAccessPermission();
- ensureValidType(type);
- if (listener == null) {
- throw new IllegalArgumentException("listener must not be null");
- }
- synchronized (mLock) {
- HdmiCecDevice device = mLogicalDevices.get(type);
- if (device != null) {
- Log.v(TAG, "Logical address already allocated. Adding listener only.");
- } else {
- int address = nativeAllocateLogicalAddress(mNativePtr, type);
- if (!HdmiCec.isValidAddress(address)) {
- Log.e(TAG, "Logical address was not allocated");
- return null;
- } else {
- device = HdmiCecDevice.create(HdmiCecService.this, type);
- if (device == null) {
- Log.e(TAG, "Device type not supported yet.");
- return null;
- }
- device.initialize();
- mLogicalDevices.put(type, device);
- }
- }
-
- // Adds the listener and its monitor
- ListenerRecord record = new ListenerRecord(listener, type);
- try {
- listener.asBinder().linkToDeath(record, 0);
- } catch (RemoteException e) {
- Log.w(TAG, "Listener already died");
- if (!device.hasListener()) {
- removeLogicalDeviceLocked(type);
- }
- return null;
- }
- mListenerRecords.add(record);
- device.addListener(listener);
- return device.getToken();
- }
- }
-
- @Override
- public void sendActiveSource(IBinder b) {
- enforceAccessPermission();
- synchronized (mLock) {
- HdmiCecDevice device = getLogicalDeviceLocked(b);
- device.sendActiveSource(nativeGetPhysicalAddress(mNativePtr));
- }
- }
-
- @Override
- public void sendInactiveSource(IBinder b) {
- enforceAccessPermission();
- synchronized (mLock) {
- HdmiCecDevice device = getLogicalDeviceLocked(b);
- device.sendInactiveSource(nativeGetPhysicalAddress(mNativePtr));
- }
- }
-
- @Override
- public void sendImageViewOn(IBinder b) {
- enforceAccessPermission();
- synchronized (mLock) {
- HdmiCecDevice device = getLogicalDeviceLocked(b);
- device.sendImageViewOn();
- }
- }
-
- @Override
- public void sendTextViewOn(IBinder b) {
- enforceAccessPermission();
- synchronized (mLock) {
- HdmiCecDevice device = getLogicalDeviceLocked(b);
- device.sendTextViewOn();
- }
- }
-
- public void sendGiveDevicePowerStatus(IBinder b, int address) {
- enforceAccessPermission();
- synchronized (mLock) {
- HdmiCecDevice device = getLogicalDeviceLocked(b);
- nativeSendMessage(mNativePtr, device.getType(), address,
- HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, EMPTY_PARAM);
- }
- }
-
- @Override
- public boolean isTvOn(IBinder b) {
- enforceAccessPermission();
- synchronized (mLock) {
- HdmiCecDevice device = getLogicalDeviceLocked(b);
- return device.isSinkDeviceOn();
- }
- }
-
- @Override
- public void removeServiceListener(IBinder b, IHdmiCecListener listener) {
- enforceAccessPermission();
- if (listener == null) {
- throw new IllegalArgumentException("listener must not be null");
- }
- synchronized (mLock) {
- HdmiCecDevice device = getLogicalDeviceLocked(b);
- for (ListenerRecord record : mListenerRecords) {
- if (record.mType == device.getType()
- && record.mListener.asBinder() == listener.asBinder()) {
- mListenerRecords.remove(record);
- device.removeListener(record.mListener);
- if (!device.hasListener()) {
- removeLogicalDeviceLocked(record.mType);
- }
- break;
- }
- }
- }
- }
-
- @Override
- public void sendMessage(IBinder b, HdmiCecMessage message) {
- enforceAccessPermission();
- if (message == null) {
- throw new IllegalArgumentException("message must not be null");
- }
- synchronized (mLock) {
- HdmiCecDevice device = getLogicalDeviceLocked(b);
- nativeSendMessage(mNativePtr, device.getType(), message.getDestination(),
- message.getOpcode(), message.getParams());
- }
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission denial: can't dump HdmiCecService from pid="
- + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
- + " without permission " + android.Manifest.permission.DUMP);
- return;
- }
- final long ident = Binder.clearCallingIdentity();
- try {
- dumpInternal(pw);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
-
- private static native int nativeAllocateLogicalAddress(long handler, int deviceType);
- private static native void nativeRemoveLogicalAddress(long handler, int deviceType);
- private static native void nativeSendMessage(long handler, int deviceType, int destination,
- int opcode, byte[] params);
- private static native int nativeGetPhysicalAddress(long handler);
- private static native void nativeSetOsdName(long handler, byte[] name);
-}
diff --git a/services/core/java/com/android/server/hdmi/HdmiConstants.java b/services/core/java/com/android/server/hdmi/HdmiConstants.java
index a83d1ed..9c60e55 100644
--- a/services/core/java/com/android/server/hdmi/HdmiConstants.java
+++ b/services/core/java/com/android/server/hdmi/HdmiConstants.java
@@ -39,9 +39,61 @@
// Constants related to UI Command Codes.
// Refer to CEC Table 30 in HDMI Spec v1.4b.
+ static final int UI_COMMAND_POWER = 0x40;
+ static final int UI_COMMAND_VOLUME_UP = 0x41;
+ static final int UI_COMMAND_VOLUME_DOWN = 0x42;
static final int UI_COMMAND_MUTE = 0x43;
static final int UI_COMMAND_MUTE_FUNCTION = 0x65;
static final int UI_COMMAND_RESTORE_VOLUME_FUNCTION = 0x66;
+ static final int UI_COMMAND_POWER_ON_FUNCTION = 0x6D;
+
+ // Bit mask used to get the routing path of the top level device.
+ // When &'d with the path 1.2.2.0 (0x1220), for instance, gives 1.0.0.0.
+ static final int ROUTING_PATH_TOP_MASK = 0xF000;
+
+ // Flags used for setOption to CEC HAL.
+ /**
+ * When set to false, HAL does not wake up the system upon receiving
+ * <Image View On> or <Text View On>. Used when user changes the TV
+ * settings to disable the auto TV on functionality.
+ * True by default.
+ */
+ static final int FLAG_HDMI_OPTION_WAKEUP = 1;
+ /**
+ * When set to false, all the CEC commands are discarded. Used when
+ * user changes the TV settings to disable CEC functionality.
+ * True by default.
+ */
+ static final int FLAG_HDMI_OPTION_ENABLE_CEC = 2;
+ /**
+ * Setting this flag to false means Android system will stop handling
+ * CEC service and yield the control over to the microprocessor that is
+ * powered on through the standby mode. When set to true, the system
+ * will gain the control over, hence telling the microprocessor to stop
+ * handling the cec commands. This is called when system goes
+ * in and out of standby mode to notify the microprocessor that it should
+ * start/stop handling CEC commands on behalf of the system.
+ * False by default.
+ */
+ static final int FLAG_HDMI_OPTION_SYSTEM_CEC_CONTROL = 3;
+
+ static final int INVALID_PORT_ID = -1;
+ static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
+
+ // Send result codes.
+ static final int SEND_RESULT_SUCCESS = 0;
+ static final int SEND_RESULT_NAK = -1;
+ static final int SEND_RESULT_FAILURE = -2;
+
+ // Strategy for device polling.
+ // Should use "OR(|) operation of POLL_STRATEGY_XXX and POLL_ITERATION_XXX.
+ static final int POLL_STRATEGY_MASK = 0x3; // first and second bit.
+ static final int POLL_STRATEGY_REMOTES_DEVICES = 0x1;
+ static final int POLL_STRATEGY_SYSTEM_AUDIO = 0x2;
+
+ static final int POLL_ITERATION_STRATEGY_MASK = 0x30000; // first and second bit.
+ static final int POLL_ITERATION_IN_ORDER = 0x10000;
+ static final int POLL_ITERATION_REVERSE_ORDER = 0x20000;
private HdmiConstants() { /* cannot be instantiated */ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 4b78591..10da756 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -21,9 +21,13 @@
import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecDeviceInfo;
import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.HdmiHotplugEvent;
+import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.IHdmiControlService;
+import android.hardware.hdmi.IHdmiDeviceEventListener;
import android.hardware.hdmi.IHdmiHotplugEventListener;
+import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -33,16 +37,12 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
-import com.android.internal.annotations.GuardedBy;
import com.android.server.SystemService;
-import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedList;
+import java.util.Collections;
import java.util.List;
-import java.util.Locale;
/**
* Provides a service for sending and processing HDMI control messages,
@@ -54,18 +54,6 @@
// TODO: Rename the permission to HDMI_CONTROL.
private static final String PERMISSION = "android.permission.HDMI_CEC";
- static final int SEND_RESULT_SUCCESS = 0;
- static final int SEND_RESULT_NAK = -1;
- static final int SEND_RESULT_FAILURE = -2;
-
- static final int POLL_STRATEGY_MASK = 0x3; // first and second bit.
- static final int POLL_STRATEGY_REMOTES_DEVICES = 0x1;
- static final int POLL_STRATEGY_SYSTEM_AUDIO = 0x2;
-
- static final int POLL_ITERATION_STRATEGY_MASK = 0x30000; // first and second bit.
- static final int POLL_ITERATION_IN_ORDER = 0x10000;
- static final int POLL_ITERATION_REVERSE_ORDER = 0x20000;
-
/**
* Interface to report send result.
*/
@@ -98,16 +86,11 @@
// and sparse call it shares a thread to handle IO operations.
private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread");
- // A collection of FeatureAction.
- // Note that access to this collection should happen in service thread.
- private final LinkedList<FeatureAction> mActions = new LinkedList<>();
-
// Used to synchronize the access to the service.
private final Object mLock = new Object();
- // Type of logical devices hosted in the system.
- @GuardedBy("mLock")
- private final int[] mLocalDevices;
+ // Type of logical devices hosted in the system. Stored in the unmodifiable list.
+ private final List<Integer> mLocalDevices;
// List of listeners registered by callers that want to get notified of
// hotplug events.
@@ -117,28 +100,31 @@
private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords =
new ArrayList<>();
+ // List of listeners registered by callers that want to get notified of
+ // device status events.
+ private final ArrayList<IHdmiDeviceEventListener> mDeviceEventListeners = new ArrayList<>();
+
+ // List of records for device event listener to handle the the caller killed in action.
+ private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords =
+ new ArrayList<>();
+
+ // Handler running on service thread. It's used to run a task in service thread.
+ private final Handler mHandler = new Handler();
+
@Nullable
private HdmiCecController mCecController;
@Nullable
private HdmiMhlController mMhlController;
- @GuardedBy("mLock")
- // Whether ARC is "enabled" or not.
- // TODO: it may need to hold lock if it's accessed from others.
- private boolean mArcStatusEnabled = false;
-
- @GuardedBy("mLock")
- // Whether SystemAudioMode is "On" or not.
- private boolean mSystemAudioMode;
-
- // Handler running on service thread. It's used to run a task in service thread.
- private final Handler mHandler = new Handler();
+ // HDMI port information. Stored in the unmodifiable list to keep the static information
+ // from being modified.
+ private List<HdmiPortInfo> mPortInfo;
public HdmiControlService(Context context) {
super(context);
- mLocalDevices = getContext().getResources().getIntArray(
- com.android.internal.R.array.config_hdmiCecLogicalDeviceType);
+ mLocalDevices = HdmiUtils.asImmutableList(getContext().getResources().getIntArray(
+ com.android.internal.R.array.config_hdmiCecLogicalDeviceType));
}
@Override
@@ -156,14 +142,14 @@
if (mMhlController == null) {
Slog.i(TAG, "Device does not support MHL-control.");
}
-
+ mPortInfo = initPortInfo();
publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService());
// TODO: Read the preference for SystemAudioMode and initialize mSystemAudioMode and
// start to monitor the preference value and invoke SystemAudioActionFromTv if needed.
}
- private void initializeLocalDevices(final int[] deviceTypes) {
+ private void initializeLocalDevices(final List<Integer> deviceTypes) {
// A container for [Logical Address, Local device info].
final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>();
final SparseIntArray finished = new SparseIntArray();
@@ -187,7 +173,7 @@
// Once finish address allocation for all devices, notify
// it to each device.
- if (deviceTypes.length == finished.size()) {
+ if (deviceTypes.size() == finished.size()) {
notifyAddressAllocated(devices);
}
}
@@ -203,6 +189,95 @@
}
}
+ // Initialize HDMI port information. Combine the information from CEC and MHL HAL and
+ // keep them in one place.
+ private List<HdmiPortInfo> initPortInfo() {
+ HdmiPortInfo[] cecPortInfo = null;
+
+ // CEC HAL provides majority of the info while MHL does only MHL support flag for
+ // each port. Return empty array if CEC HAL didn't provide the info.
+ if (mCecController != null) {
+ cecPortInfo = mCecController.getPortInfos();
+ }
+ if (cecPortInfo == null) {
+ return Collections.emptyList();
+ }
+
+ HdmiPortInfo[] mhlPortInfo = new HdmiPortInfo[0];
+ if (mMhlController != null) {
+ // TODO: Implement plumbing logic to get MHL port information.
+ // mhlPortInfo = mMhlController.getPortInfos();
+ }
+
+ // Use the id (port number) to find the matched info between CEC and MHL to combine them
+ // into one. Leave the field `mhlSupported` to false if matched MHL entry is not found.
+ ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length);
+ for (int i = 0; i < cecPortInfo.length; ++i) {
+ HdmiPortInfo cec = cecPortInfo[i];
+ int id = cec.getId();
+ boolean mhlInfoFound = false;
+ for (HdmiPortInfo mhl : mhlPortInfo) {
+ if (id == mhl.getId()) {
+ result.add(new HdmiPortInfo(id, cec.getType(), cec.getAddress(),
+ cec.isCecSupported(), mhl.isMhlSupported(), cec.isArcSupported()));
+ mhlInfoFound = true;
+ break;
+ }
+ }
+ if (!mhlInfoFound) {
+ result.add(cec);
+ }
+ }
+
+ return Collections.unmodifiableList(result);
+ }
+
+ /**
+ * Returns HDMI port information for the given port id.
+ *
+ * @param portId HDMI port id
+ * @return {@link HdmiPortInfo} for the given port
+ */
+ HdmiPortInfo getPortInfo(int portId) {
+ // mPortInfo is an unmodifiable list and the only reference to its inner list.
+ // No lock is necessary.
+ for (HdmiPortInfo info : mPortInfo) {
+ if (portId == info.getId()) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the routing path (physical address) of the HDMI port for the given
+ * port id.
+ */
+ int portIdToPath(int portId) {
+ HdmiPortInfo portInfo = getPortInfo(portId);
+ if (portInfo == null) {
+ Slog.e(TAG, "Cannot find the port info: " + portId);
+ return HdmiConstants.INVALID_PHYSICAL_ADDRESS;
+ }
+ return portInfo.getAddress();
+ }
+
+ /**
+ * Returns the id of HDMI port located at the top of the hierarchy of
+ * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance,
+ * the port id to be returned is the ID associated with the port address
+ * 0x1000 (1.0.0.0) which is the topmost path of the given routing path.
+ */
+ int pathToPortId(int path) {
+ int portAddress = path & HdmiConstants.ROUTING_PATH_TOP_MASK;
+ for (HdmiPortInfo info : mPortInfo) {
+ if (portAddress == info.getAddress()) {
+ return info.getId();
+ }
+ }
+ return HdmiConstants.INVALID_PORT_ID;
+ }
+
/**
* Returns {@link Looper} for IO operation.
*
@@ -236,84 +311,36 @@
return mCecController.getVendorId();
}
- /**
- * Returns a list of {@link HdmiCecDeviceInfo}.
- *
- * @param includeLocalDevice whether to include local devices
- */
- List<HdmiCecDeviceInfo> getDeviceInfoList(boolean includeLocalDevice) {
+ HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) {
assertRunOnServiceThread();
- return mCecController.getDeviceInfoList(includeLocalDevice);
+ HdmiCecLocalDeviceTv tv = tv();
+ if (tv == null) {
+ return null;
+ }
+ return tv.getDeviceInfo(logicalAddress);
}
/**
- * Add and start a new {@link FeatureAction} to the action queue.
- *
- * @param action {@link FeatureAction} to add and start
+ * Returns version of CEC.
*/
- void addAndStartAction(final FeatureAction action) {
- // TODO: may need to check the number of stale actions.
- runOnServiceThread(new Runnable() {
- @Override
- public void run() {
- mActions.add(action);
- action.start();
- }
- });
+ int getCecVersion() {
+ return mCecController.getVersion();
}
- void setSystemAudioMode(boolean on) {
- synchronized (mLock) {
- mSystemAudioMode = on;
- }
- }
-
- boolean getSystemAudioMode() {
- synchronized (mLock) {
- return mSystemAudioMode;
- }
- }
-
- // See if we have an action of a given type in progress.
- private <T extends FeatureAction> boolean hasAction(final Class<T> clazz) {
- for (FeatureAction action : mActions) {
- if (action.getClass().equals(clazz)) {
+ /**
+ * Whether a device of the specified physical address is connected to ARC enabled port.
+ */
+ boolean isConnectedToArcPort(int physicalAddress) {
+ for (HdmiPortInfo portInfo : mPortInfo) {
+ if (hasSameTopPort(portInfo.getAddress(), physicalAddress)
+ && portInfo.isArcSupported()) {
return true;
}
}
return false;
}
- /**
- * Remove the given {@link FeatureAction} object from the action queue.
- *
- * @param action {@link FeatureAction} to remove
- */
- void removeAction(final FeatureAction action) {
- assertRunOnServiceThread();
- mActions.remove(action);
- }
-
- // Remove all actions matched with the given Class type.
- private <T extends FeatureAction> void removeAction(final Class<T> clazz) {
- removeActionExcept(clazz, null);
- }
-
- // Remove all actions matched with the given Class type besides |exception|.
- <T extends FeatureAction> void removeActionExcept(final Class<T> clazz,
- final FeatureAction exception) {
- assertRunOnServiceThread();
- Iterator<FeatureAction> iter = mActions.iterator();
- while (iter.hasNext()) {
- FeatureAction action = iter.next();
- if (action != exception && action.getClass().equals(clazz)) {
- action.clear();
- mActions.remove(action);
- }
- }
- }
-
- private void runOnServiceThread(Runnable runnable) {
+ void runOnServiceThread(Runnable runnable) {
mHandler.post(runnable);
}
@@ -328,23 +355,6 @@
}
/**
- * Change ARC status into the given {@code enabled} status.
- *
- * @return {@code true} if ARC was in "Enabled" status
- */
- boolean setArcStatus(boolean enabled) {
- synchronized (mLock) {
- boolean oldStatus = mArcStatusEnabled;
- // 1. Enable/disable ARC circuit.
- // TODO: call set_audio_return_channel of hal interface.
-
- // 2. Update arc status;
- mArcStatusEnabled = enabled;
- return oldStatus;
- }
- }
-
- /**
* Transmit a CEC command to CEC bus.
*
* @param command CEC command to send out
@@ -358,52 +368,24 @@
mCecController.sendCommand(command, null);
}
- /**
- * Add a new {@link HdmiCecDeviceInfo} to controller.
- *
- * @param deviceInfo new device information object to add
- */
- void addDeviceInfo(HdmiCecDeviceInfo deviceInfo) {
- // TODO: Implement this.
+ boolean handleCecCommand(HdmiCecMessage message) {
+ return dispatchMessageToLocalDevice(message);
}
- boolean handleCecCommand(HdmiCecMessage message) {
- // Commands that queries system information replies directly instead
- // of creating FeatureAction because they are state-less.
- switch (message.getOpcode()) {
- case HdmiCec.MESSAGE_GET_MENU_LANGUAGE:
- handleGetMenuLanguage(message);
+ void setAudioReturnChannel(boolean enabled) {
+ mCecController.setAudioReturnChannel(enabled);
+ }
+
+ private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) {
+ for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
+ if (device.dispatchMessage(message)
+ && message.getDestination() != HdmiCec.ADDR_BROADCAST) {
return true;
- case HdmiCec.MESSAGE_GIVE_OSD_NAME:
- handleGiveOsdName(message);
- return true;
- case HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS:
- handleGivePhysicalAddress(message);
- return true;
- case HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID:
- handleGiveDeviceVendorId(message);
- return true;
- case HdmiCec.MESSAGE_GET_CEC_VERSION:
- handleGetCecVersion(message);
- return true;
- case HdmiCec.MESSAGE_INITIATE_ARC:
- handleInitiateArc(message);
- return true;
- case HdmiCec.MESSAGE_TERMINATE_ARC:
- handleTerminateArc(message);
- return true;
- case HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS:
- handleReportPhysicalAddress(message);
- return true;
- case HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE:
- handleSetSystemAudioMode(message);
- return true;
- case HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
- handleSystemAudioModeStatus(message);
- return true;
- default:
- return dispatchMessageToAction(message);
+ }
}
+
+ Slog.w(TAG, "Unhandled cec command:" + message);
+ return false;
}
/**
@@ -413,7 +395,13 @@
* @param connected whether to be plugged in or not
*/
void onHotplug(int portNo, boolean connected) {
- // TODO: Start "RequestArcInitiationAction" if ARC port.
+ assertRunOnServiceThread();
+
+ for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
+ device.onHotplug(portNo, connected);
+ }
+
+ announceHotplugEvent(portNo, connected);
}
/**
@@ -430,187 +418,37 @@
}
private int checkPollStrategy(int pickStrategy) {
- int strategy = pickStrategy & POLL_STRATEGY_MASK;
+ int strategy = pickStrategy & HdmiConstants.POLL_STRATEGY_MASK;
if (strategy == 0) {
throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy);
}
- int iterationStrategy = pickStrategy & POLL_ITERATION_STRATEGY_MASK;
+ int iterationStrategy = pickStrategy & HdmiConstants.POLL_ITERATION_STRATEGY_MASK;
if (iterationStrategy == 0) {
throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy);
}
return strategy | iterationStrategy;
}
+ List<HdmiCecLocalDevice> getAllLocalDevices() {
+ assertRunOnServiceThread();
+ return mCecController.getLocalDeviceList();
+ }
- /**
- * Launch device discovery sequence. It starts with clearing the existing device info list.
- * Note that it assumes that logical address of all local devices is already allocated.
- *
- * @param sourceAddress a logical address of tv
- */
- void launchDeviceDiscovery(final int sourceAddress) {
- // At first, clear all existing device infos.
- mCecController.clearDeviceInfoList();
+ Object getServiceLock() {
+ return mLock;
+ }
- // TODO: check whether TV is one of local devices.
- DeviceDiscoveryAction action = new DeviceDiscoveryAction(this, sourceAddress,
- new DeviceDiscoveryCallback() {
- @Override
- public void onDeviceDiscoveryDone(List<HdmiCecDeviceInfo> deviceInfos) {
- for (HdmiCecDeviceInfo info : deviceInfos) {
- mCecController.addDeviceInfo(info);
- }
-
- // Add device info of all local devices.
- for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
- mCecController.addDeviceInfo(device.getDeviceInfo());
- }
-
- addAndStartAction(new HotplugDetectionAction(HdmiControlService.this,
- sourceAddress));
- }
- });
- addAndStartAction(action);
+ void setAudioStatus(boolean mute, int volume) {
+ // TODO: Hook up with AudioManager.
}
private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) {
- // TODO: get device name read from system configuration.
- String displayName = HdmiCec.getDefaultDeviceName(logicalAddress);
+ // TODO: find better name instead of model name.
+ String displayName = Build.MODEL;
return new HdmiCecDeviceInfo(logicalAddress,
getPhysicalAddress(), deviceType, getVendorId(), displayName);
}
- private void handleReportPhysicalAddress(HdmiCecMessage message) {
- // At first, try to consume it.
- if (dispatchMessageToAction(message)) {
- return;
- }
-
- // Ignore if [Device Discovery Action] is going on.
- if (hasAction(DeviceDiscoveryAction.class)) {
- Slog.i(TAG, "Ignore unrecognizable <Report Physical Address> "
- + "because Device Discovery Action is on-going:" + message);
- return;
- }
-
- // TODO: start new device action.
- }
-
- private void handleInitiateArc(HdmiCecMessage message){
- // In case where <Initiate Arc> is started by <Request ARC Initiation>
- // need to clean up RequestArcInitiationAction.
- removeAction(RequestArcInitiationAction.class);
- SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this,
- message.getDestination(), message.getSource(), true);
- addAndStartAction(action);
- }
-
- private void handleTerminateArc(HdmiCecMessage message) {
- // In case where <Terminate Arc> is started by <Request ARC Termination>
- // need to clean up RequestArcInitiationAction.
- // TODO: check conditions of power status by calling is_connected api
- // to be added soon.
- removeAction(RequestArcTerminationAction.class);
- SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this,
- message.getDestination(), message.getSource(), false);
- addAndStartAction(action);
- }
-
- private void handleGetCecVersion(HdmiCecMessage message) {
- int version = mCecController.getVersion();
- HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(),
- message.getSource(),
- version);
- sendCecCommand(cecMessage);
- }
-
- private void handleGiveDeviceVendorId(HdmiCecMessage message) {
- int vendorId = mCecController.getVendorId();
- HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
- message.getDestination(), vendorId);
- sendCecCommand(cecMessage);
- }
-
- private void handleGivePhysicalAddress(HdmiCecMessage message) {
- int physicalAddress = mCecController.getPhysicalAddress();
- int deviceType = HdmiCec.getTypeFromAddress(message.getDestination());
- HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
- message.getDestination(), physicalAddress, deviceType);
- sendCecCommand(cecMessage);
- }
-
- private void handleGiveOsdName(HdmiCecMessage message) {
- // TODO: read device name from settings or property.
- String name = HdmiCec.getDefaultDeviceName(message.getDestination());
- HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand(
- message.getDestination(), message.getSource(), name);
- if (cecMessage != null) {
- sendCecCommand(cecMessage);
- } else {
- Slog.w(TAG, "Failed to build <Get Osd Name>:" + name);
- }
- }
-
- private void handleGetMenuLanguage(HdmiCecMessage message) {
- // Only 0 (TV), 14 (specific use) can answer.
- if (message.getDestination() != HdmiCec.ADDR_TV
- && message.getDestination() != HdmiCec.ADDR_SPECIFIC_USE) {
- Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString());
- sendCecCommand(
- HdmiCecMessageBuilder.buildFeatureAbortCommand(message.getDestination(),
- message.getSource(), HdmiCec.MESSAGE_GET_MENU_LANGUAGE,
- HdmiConstants.ABORT_UNRECOGNIZED_MODE));
- return;
- }
-
- HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand(
- message.getDestination(),
- Locale.getDefault().getISO3Language());
- // TODO: figure out how to handle failed to get language code.
- if (command != null) {
- sendCecCommand(command);
- } else {
- Slog.w(TAG, "Failed to respond to <Get Menu Language>: " + message.toString());
- }
- }
-
- private boolean dispatchMessageToAction(HdmiCecMessage message) {
- for (FeatureAction action : mActions) {
- if (action.processCommand(message)) {
- return true;
- }
- }
- Slog.w(TAG, "Unsupported cec command:" + message);
- return false;
- }
-
- private void handleSetSystemAudioMode(HdmiCecMessage message) {
- if (dispatchMessageToAction(message) || !isMessageForSystemAudio(message)) {
- return;
- }
- SystemAudioActionFromAvr action = new SystemAudioActionFromAvr(this,
- message.getDestination(), message.getSource(),
- HdmiUtils.parseCommandParamSystemAudioStatus(message));
- addAndStartAction(action);
- }
-
- private void handleSystemAudioModeStatus(HdmiCecMessage message) {
- if (!isMessageForSystemAudio(message)) {
- return;
- }
- setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message));
- }
-
- private boolean isMessageForSystemAudio(HdmiCecMessage message) {
- if (message.getSource() != HdmiCec.ADDR_AUDIO_SYSTEM
- || message.getDestination() != HdmiCec.ADDR_TV
- || getAvrDeviceInfo() == null) {
- Slog.w(TAG, "Skip abnormal CecMessage: " + message);
- return false;
- }
- return true;
- }
-
// Record class that monitors the event of the caller of being killed. Used to clean up
// the listener list and record list accordingly.
private final class HotplugEventListenerRecord implements IBinder.DeathRecipient {
@@ -629,8 +467,20 @@
}
}
- void addCecDevice(HdmiCecDeviceInfo info) {
- mCecController.addDeviceInfo(info);
+ private final class DeviceEventListenerRecord implements IBinder.DeathRecipient {
+ private final IHdmiDeviceEventListener mListener;
+
+ public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ mDeviceEventListenerRecords.remove(this);
+ mDeviceEventListeners.remove(mListener);
+ }
+ }
}
private void enforceAccessPermission() {
@@ -641,9 +491,29 @@
@Override
public int[] getSupportedTypes() {
enforceAccessPermission();
- synchronized (mLock) {
- return mLocalDevices;
+ // mLocalDevices is an unmodifiable list - no lock necesary.
+ int[] localDevices = new int[mLocalDevices.size()];
+ for (int i = 0; i < localDevices.length; ++i) {
+ localDevices[i] = mLocalDevices.get(i);
}
+ return localDevices;
+ }
+
+ @Override
+ public void deviceSelect(final int logicalAddress, final IHdmiControlCallback callback) {
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ HdmiCecLocalDeviceTv tv = tv();
+ if (tv == null) {
+ Slog.w(TAG, "Local playback device not available");
+ invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
+ return;
+ }
+ tv.deviceSelect(logicalAddress, callback);
+ }
+ });
}
@Override
@@ -689,53 +559,55 @@
}
});
}
+
+ @Override
+ public void addDeviceEventListener(final IHdmiDeviceEventListener listener) {
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ HdmiControlService.this.addDeviceEventListener(listener);
+ }
+ });
+ }
+
+ @Override
+ public void portSelect(int portId, IHdmiControlCallback callback) {
+ // TODO: Implement this
+ }
+
+ @Override
+ public void sendKeyEvent(int keyCode, boolean isPressed) {
+ // TODO: Implement this
+ }
+
+ @Override
+ public List<HdmiPortInfo> getPortInfo() {
+ enforceAccessPermission();
+ return mPortInfo;
+ }
}
- private void oneTouchPlay(IHdmiControlCallback callback) {
- if (hasAction(OneTouchPlayAction.class)) {
- Slog.w(TAG, "oneTouchPlay already in progress");
- invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS);
- return;
- }
- HdmiCecLocalDevice source = mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK);
+ private void oneTouchPlay(final IHdmiControlCallback callback) {
+ assertRunOnServiceThread();
+ HdmiCecLocalDevicePlayback source = playback();
if (source == null) {
Slog.w(TAG, "Local playback device not available");
invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
return;
}
- // TODO: Consider the case of multiple TV sets. For now we always direct the command
- // to the primary one.
- OneTouchPlayAction action = OneTouchPlayAction.create(this,
- source.getDeviceInfo().getLogicalAddress(),
- source.getDeviceInfo().getPhysicalAddress(), HdmiCec.ADDR_TV, callback);
- if (action == null) {
- Slog.w(TAG, "Cannot initiate oneTouchPlay");
- invokeCallback(callback, HdmiCec.RESULT_EXCEPTION);
- return;
- }
- addAndStartAction(action);
+ source.oneTouchPlay(callback);
}
- private void queryDisplayStatus(IHdmiControlCallback callback) {
- if (hasAction(DevicePowerStatusAction.class)) {
- Slog.w(TAG, "queryDisplayStatus already in progress");
- invokeCallback(callback, HdmiCec.RESULT_ALREADY_IN_PROGRESS);
- return;
- }
- HdmiCecLocalDevice source = mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK);
+ private void queryDisplayStatus(final IHdmiControlCallback callback) {
+ assertRunOnServiceThread();
+ HdmiCecLocalDevicePlayback source = playback();
if (source == null) {
Slog.w(TAG, "Local playback device not available");
invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
return;
}
- DevicePowerStatusAction action = DevicePowerStatusAction.create(this,
- source.getDeviceInfo().getLogicalAddress(), HdmiCec.ADDR_TV, callback);
- if (action == null) {
- Slog.w(TAG, "Cannot initiate queryDisplayStatus");
- invokeCallback(callback, HdmiCec.RESULT_EXCEPTION);
- return;
- }
- addAndStartAction(action);
+ source.queryDisplayStatus(callback);
}
private void addHotplugEventListener(IHdmiHotplugEventListener listener) {
@@ -765,6 +637,19 @@
}
}
+ private void addDeviceEventListener(IHdmiDeviceEventListener listener) {
+ synchronized (mLock) {
+ for (DeviceEventListenerRecord record : mDeviceEventListenerRecords) {
+ if (record.mListener.asBinder() == listener.asBinder()) {
+ listener.asBinder().unlinkToDeath(record, 0);
+ mDeviceEventListenerRecords.remove(record);
+ break;
+ }
+ }
+ mHotplugEventListeners.remove(listener);
+ }
+ }
+
private void invokeCallback(IHdmiControlCallback callback, int result) {
try {
callback.onComplete(result);
@@ -773,16 +658,34 @@
}
}
- HdmiCecDeviceInfo getAvrDeviceInfo() {
- return mCecController.getDeviceInfo(HdmiCec.ADDR_AUDIO_SYSTEM);
+ private void announceHotplugEvent(int portNo, boolean connected) {
+ HdmiHotplugEvent event = new HdmiHotplugEvent(portNo, connected);
+ synchronized (mLock) {
+ for (IHdmiHotplugEventListener listener : mHotplugEventListeners) {
+ invokeHotplugEventListener(listener, event);
+ }
+ }
}
- void setAudioStatus(boolean mute, int volume) {
- // TODO: Hook up with AudioManager.
+ private void invokeHotplugEventListener(IHdmiHotplugEventListener listener,
+ HdmiHotplugEvent event) {
+ try {
+ listener.onReceived(event);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e);
+ }
}
- boolean isInPresetInstallationMode() {
- // TODO: Implement this.
- return false;
+ private static boolean hasSameTopPort(int path1, int path2) {
+ return (path1 & HdmiConstants.ROUTING_PATH_TOP_MASK)
+ == (path2 & HdmiConstants.ROUTING_PATH_TOP_MASK);
+ }
+
+ private HdmiCecLocalDeviceTv tv() {
+ return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCec.DEVICE_TV);
+ }
+
+ private HdmiCecLocalDevicePlayback playback() {
+ return (HdmiCecLocalDevicePlayback) mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK);
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index ef128ed1..9b7cc8d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -19,6 +19,11 @@
import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecMessage;
import android.util.Slog;
+import android.util.SparseArray;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
* Various utilities to handle HDMI CEC messages.
@@ -71,4 +76,49 @@
return cmd.getParams().length > 0
&& cmd.getParams()[0] == HdmiConstants.SYSTEM_AUDIO_STATUS_ON;
}
+
+ /**
+ * Convert integer array to list of {@link Integer}.
+ *
+ * <p>The result is immutable.
+ *
+ * @param is integer array
+ * @return {@link List} instance containing the elements in the given array
+ */
+ static List<Integer> asImmutableList(final int[] is) {
+ ArrayList<Integer> list = new ArrayList<>(is.length);
+ for (int type : is) {
+ list.add(type);
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /**
+ * Assemble two bytes into single integer value.
+ *
+ * @param data to be assembled
+ * @return assembled value
+ */
+ static int twoBytesToInt(byte[] data) {
+ return ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
+ }
+
+ /**
+ * Assemble three bytes into single integer value.
+ *
+ * @param data to be assembled
+ * @return assembled value
+ */
+ static int threeBytesToInt(byte[] data) {
+ return ((data[0] & 0xFF) << 16) | ((data[1] & 0xFF) << 8) | (data[2] & 0xFF);
+ }
+
+ static <T> List<T> sparseArrayToList(SparseArray<T> array) {
+ ArrayList<T> list = new ArrayList<>();
+ for (int i = 0; i < array.size(); ++i) {
+ list.add(array.valueAt(i));
+ }
+ return list;
+ }
+
}
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index c905c76..647cc88 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -52,11 +52,10 @@
/**
* Constructor
*
- * @param service instance of {@link HdmiControlService}
- * @param sourceAddress logical address of a device that initiate this action
+ * @param source {@link HdmiCecLocalDevice} instance
*/
- HotplugDetectionAction(HdmiControlService service, int sourceAddress) {
- super(service, sourceAddress);
+ HotplugDetectionAction(HdmiCecLocalDevice source) {
+ super(source);
}
@Override
@@ -90,13 +89,27 @@
}
}
+ /**
+ * Start device polling immediately.
+ */
+ void pollAllDevicesNow() {
+ // Clear existing timer to avoid overlapped execution
+ mActionTimer.clearTimerMessage();
+
+ mTimeoutCount = 0;
+ mState = STATE_WAIT_FOR_NEXT_POLLING;
+ pollAllDevices();
+
+ addTimer(mState, POLLING_INTERVAL_MS);
+ }
+
// This method is called every 5 seconds.
private void pollDevices() {
// All device check called every 15 seconds.
if (mTimeoutCount == 0) {
pollAllDevices();
} else {
- if (mService.getSystemAudioMode()) {
+ if (tv().getSystemAudioMode()) {
pollAudioSystem();
}
}
@@ -107,29 +120,29 @@
private void pollAllDevices() {
Slog.v(TAG, "Poll all devices.");
- mService.pollDevices(new DevicePollingCallback() {
+ pollDevices(new DevicePollingCallback() {
@Override
public void onPollingFinished(List<Integer> ackedAddress) {
checkHotplug(ackedAddress, false);
}
- }, HdmiControlService.POLL_ITERATION_IN_ORDER
- | HdmiControlService.POLL_STRATEGY_REMOTES_DEVICES, POLL_RETRY_COUNT);
+ }, HdmiConstants.POLL_ITERATION_IN_ORDER
+ | HdmiConstants.POLL_STRATEGY_REMOTES_DEVICES, POLL_RETRY_COUNT);
}
private void pollAudioSystem() {
Slog.v(TAG, "Poll audio system.");
- mService.pollDevices(new DevicePollingCallback() {
+ pollDevices(new DevicePollingCallback() {
@Override
public void onPollingFinished(List<Integer> ackedAddress) {
- checkHotplug(ackedAddress, false);
+ checkHotplug(ackedAddress, true);
}
- }, HdmiControlService.POLL_ITERATION_IN_ORDER
- | HdmiControlService.POLL_STRATEGY_SYSTEM_AUDIO, POLL_RETRY_COUNT);
+ }, HdmiConstants.POLL_ITERATION_IN_ORDER
+ | HdmiConstants.POLL_STRATEGY_SYSTEM_AUDIO, POLL_RETRY_COUNT);
}
private void checkHotplug(List<Integer> ackedAddress, boolean audioOnly) {
- BitSet currentInfos = infoListToBitSet(mService.getDeviceInfoList(false), audioOnly);
+ BitSet currentInfos = infoListToBitSet(tv().getDeviceInfoList(false), audioOnly);
BitSet polledResult = addressListToBitSet(ackedAddress);
// At first, check removed devices.
@@ -180,14 +193,55 @@
}
private void addDevice(int addedAddress) {
- // TODO: implement this.
+ // Send <Give Physical Address>.
+ sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(getSourceAddress(),
+ addedAddress));
}
private void removeDevice(int removedAddress) {
- // TODO: implements following steps.
- // 1. Launch routing control sequence
- // 2. Stop one touch play sequence if removed device is the device to be selected.
- // 3. If audio system, start system audio off and arc off
- // 4. Inform device remove to others
+ // TODO: move the following logic to local device once move many logic to
+ // local device.
+ mayChangeRoutingPath(removedAddress);
+ mayCancelDeviceSelect(removedAddress);
+ mayCancelOneTouchRecord(removedAddress);
+ mayDisableSystemAudioAndARC(removedAddress);
+
+ tv().removeCecDevice(removedAddress);
+ }
+
+ private void mayChangeRoutingPath(int address) {
+ // TODO: if removed address is current active source, it should change active source
+ // path new one. we can keep previous selection or can choose default input,
+ // such as internal tuner. Consider send intent to app so that app
+ // can handle it.
+ }
+
+ private void mayCancelDeviceSelect(int address) {
+ List<DeviceSelectAction> actions = getActions(DeviceSelectAction.class);
+ if (actions.isEmpty()) {
+ return;
+ }
+
+ // Should ave only one Device Select Action
+ DeviceSelectAction action = actions.get(0);
+ if (action.getTargetAddress() == address) {
+ removeAction(DeviceSelectAction.class);
+ }
+ }
+
+ private void mayCancelOneTouchRecord(int address) {
+ // TODO: implement this.
+ }
+
+ private void mayDisableSystemAudioAndARC(int address) {
+ if (HdmiCec.getTypeFromAddress(address) != HdmiCec.DEVICE_AUDIO_SYSTEM) {
+ return;
+ }
+
+ // Turn off system audio mode.
+ tv().setSystemAudioMode(false);
+ if (tv().getArcStatus()) {
+ addAndStartAction(new RequestArcTerminationAction(localDevice(), address));
+ }
}
}
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index 156bbbe..4a49f09 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -48,6 +48,7 @@
private final int mDeviceLogicalAddress;
private final int mDevicePhysicalAddress;
+ private final boolean mRequireRoutingChange;
private int mVendorId;
private String mDisplayName;
@@ -55,25 +56,46 @@
/**
* Constructor.
*
- * @param service {@link HdmiControlService} instance
- * @param sourceAddress logical address to be used as source address
+ * @param source {@link HdmiCecLocalDevice} instance
* @param deviceLogicalAddress logical address of the device in interest
* @param devicePhysicalAddress physical address of the device in interest
+ * @param requireRoutingChange whether to initiate routing change or not
*/
- NewDeviceAction(HdmiControlService service, int sourceAddress, int deviceLogicalAddress,
- int devicePhysicalAddress) {
- super(service, sourceAddress);
+ NewDeviceAction(HdmiCecLocalDevice source, int deviceLogicalAddress,
+ int devicePhysicalAddress, boolean requireRoutingChange) {
+ super(source);
mDeviceLogicalAddress = deviceLogicalAddress;
mDevicePhysicalAddress = devicePhysicalAddress;
mVendorId = HdmiCec.UNKNOWN_VENDOR_ID;
+ mRequireRoutingChange = requireRoutingChange;
}
@Override
public boolean start() {
- sendCommand(
- HdmiCecMessageBuilder.buildGiveOsdNameCommand(mSourceAddress,
- mDeviceLogicalAddress));
+ if (HdmiCec.getTypeFromAddress(getSourceAddress()) == HdmiCec.DEVICE_AUDIO_SYSTEM) {
+ if (tv().getAvrDeviceInfo() == null) {
+ // TODO: Start system audio initiation action
+ }
+
+ // If new device is connected through ARC enabled port,
+ // initiates ARC channel establishment.
+ if (tv().isConnectedToArcPort(mDevicePhysicalAddress)) {
+ addAndStartAction(new RequestArcInitiationAction(localDevice(),
+ mDeviceLogicalAddress));
+ }
+ }
+
+ if (mRequireRoutingChange) {
+ startRoutingChange();
+ }
+
mState = STATE_WAITING_FOR_SET_OSD_NAME;
+ if (mayProcessCommandIfCached(mDeviceLogicalAddress, HdmiCec.MESSAGE_SET_OSD_NAME)) {
+ return true;
+ }
+
+ sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(getSourceAddress(),
+ mDeviceLogicalAddress));
addTimer(mState, TIMEOUT_MS);
return true;
}
@@ -99,13 +121,11 @@
} catch (UnsupportedEncodingException e) {
Slog.e(TAG, "Failed to get OSD name: " + e.getMessage());
}
- mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
requestVendorId();
return true;
} else if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) {
- int requestOpcode = params[1] & 0xff;
+ int requestOpcode = params[1] & 0xFF;
if (requestOpcode == HdmiCec.MESSAGE_SET_OSD_NAME) {
- mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
requestVendorId();
return true;
}
@@ -113,8 +133,7 @@
} else if (mState == STATE_WAITING_FOR_DEVICE_VENDOR_ID) {
if (opcode == HdmiCec.MESSAGE_DEVICE_VENDOR_ID) {
if (params.length == 3) {
- mVendorId = ((params[0] & 0xff) << 16) + ((params[1] & 0xff) << 8)
- + (params[2] & 0xff);
+ mVendorId = HdmiUtils.threeBytesToInt(params);
} else {
Slog.e(TAG, "Failed to get device vendor ID: ");
}
@@ -122,7 +141,7 @@
finish();
return true;
} else if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) {
- int requestOpcode = params[1] & 0xff;
+ int requestOpcode = params[1] & 0xFF;
if (requestOpcode == HdmiCec.MESSAGE_DEVICE_VENDOR_ID) {
addDeviceInfo();
finish();
@@ -133,8 +152,38 @@
return false;
}
+ private void startRoutingChange() {
+ // Stop existing routing control.
+ removeAction(RoutingControlAction.class);
+
+ // Send routing change. The the address is a path of the active port.
+ int newPath = toTopMostPortPath(mDevicePhysicalAddress);
+ sendCommand(HdmiCecMessageBuilder.buildRoutingChange(getSourceAddress(),
+ localDevice().getActivePath(), newPath));
+ addAndStartAction(new RoutingControlAction(localDevice(),
+ localDevice().pathToPortId(newPath), null));
+ }
+
+ private static int toTopMostPortPath(int physicalAddress) {
+ return physicalAddress & HdmiConstants.ROUTING_PATH_TOP_MASK;
+ }
+
+ private boolean mayProcessCommandIfCached(int destAddress, int opcode) {
+ HdmiCecMessage message = getCecMessageCache().getMessage(destAddress, opcode);
+ if (message != null) {
+ return processCommand(message);
+ }
+ return false;
+ }
+
private void requestVendorId() {
- sendCommand(HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(mSourceAddress,
+ // At first, transit to waiting status for <Device Vendor Id>.
+ mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
+ // If the message is already in cache, process it.
+ if (mayProcessCommandIfCached(mDeviceLogicalAddress, HdmiCec.MESSAGE_DEVICE_VENDOR_ID)) {
+ return;
+ }
+ sendCommand(HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(getSourceAddress(),
mDeviceLogicalAddress));
addTimer(mState, TIMEOUT_MS);
}
@@ -143,7 +192,7 @@
if (mDisplayName == null) {
mDisplayName = HdmiCec.getDefaultDeviceName(mDeviceLogicalAddress);
}
- mService.addDeviceInfo(new HdmiCecDeviceInfo(
+ tv().addCecDevice(new HdmiCecDeviceInfo(
mDeviceLogicalAddress, mDevicePhysicalAddress,
HdmiCec.getTypeFromAddress(mDeviceLogicalAddress),
mVendorId, mDisplayName));
@@ -156,7 +205,6 @@
}
if (state == STATE_WAITING_FOR_SET_OSD_NAME) {
// Osd name request timed out. Try vendor id
- mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID;
requestVendorId();
} else if (state == STATE_WAITING_FOR_DEVICE_VENDOR_ID) {
// vendor id timed out. Go ahead creating the device info what we've got so far.
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 69fad13..e0a3a8b 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -30,7 +30,7 @@
* <p>Package-private, accessed by {@link HdmiControlService} only.
*/
-public final class OneTouchPlayAction extends FeatureAction {
+final class OneTouchPlayAction extends FeatureAction {
private static final String TAG = "OneTouchPlayAction";
// State in which the action is waiting for <Report Power Status>. In normal situation
@@ -48,34 +48,32 @@
// We wait up to RESPONSE_TIMEOUT_MS * LOOP_COUNTER_MAX = 20 seconds.
private static final int LOOP_COUNTER_MAX = 10;
- private final int mSourcePath;
private final int mTargetAddress;
private final IHdmiControlCallback mCallback;
private int mPowerStatusCounter = 0;
// Factory method. Ensures arguments are valid.
- static OneTouchPlayAction create(HdmiControlService service, int sourceAddress,
- int sourcePath, int targetAddress, IHdmiControlCallback callback) {
- if (service == null || callback == null) {
+ static OneTouchPlayAction create(HdmiCecLocalDevice source,
+ int targetAddress, IHdmiControlCallback callback) {
+ if (source == null || callback == null) {
Slog.e(TAG, "Wrong arguments");
return null;
}
- return new OneTouchPlayAction(service, sourceAddress, sourcePath, targetAddress, callback);
+ return new OneTouchPlayAction(source, targetAddress,
+ callback);
}
- private OneTouchPlayAction(HdmiControlService service, int sourceAddress, int sourcePath,
- int targetAddress, IHdmiControlCallback callback) {
- super(service, sourceAddress);
- mSourcePath = sourcePath;
+ private OneTouchPlayAction(HdmiCecLocalDevice localDevice, int targetAddress,
+ IHdmiControlCallback callback) {
+ super(localDevice);
mTargetAddress = targetAddress;
mCallback = callback;
}
@Override
boolean start() {
- mService.sendCecCommand(
- HdmiCecMessageBuilder.buildTextViewOn(mSourceAddress, mTargetAddress));
+ sendCommand(HdmiCecMessageBuilder.buildTextViewOn(getSourceAddress(), mTargetAddress));
broadcastActiveSource();
queryDevicePowerStatus();
mState = STATE_WAITING_FOR_REPORT_POWER_STATUS;
@@ -84,13 +82,12 @@
}
private void broadcastActiveSource() {
- mService.sendCecCommand(
- HdmiCecMessageBuilder.buildActiveSource(mSourceAddress, mSourcePath));
+ sendCommand(HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(), getSourcePath()));
}
private void queryDevicePowerStatus() {
- mService.sendCecCommand(
- HdmiCecMessageBuilder.buildGiveDevicePowerStatus(mSourceAddress, mTargetAddress));
+ sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(),
+ mTargetAddress));
}
@Override
diff --git a/services/core/java/com/android/server/hdmi/RequestArcAction.java b/services/core/java/com/android/server/hdmi/RequestArcAction.java
index 08ca306..a2e08f1 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcAction.java
@@ -35,16 +35,14 @@
/**
* @Constructor
*
- * @param service {@link HdmiControlService} instance
- * @param sourceAddress logical address to be used as source address. It should
- * TV type
+ * @param source {@link HdmiCecLocalDevice} instance
* @param avrAddress address of AV receiver. It should be AUDIO_SYSTEM type
* @throw IllegalArugmentException if device type of sourceAddress and avrAddress
* is invalid
*/
- RequestArcAction(HdmiControlService service, int sourceAddress, int avrAddress) {
- super(service, sourceAddress);
- HdmiUtils.verifyAddressType(sourceAddress, HdmiCec.DEVICE_TV);
+ RequestArcAction(HdmiCecLocalDevice source, int avrAddress) {
+ super(source);
+ HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV);
HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
mAvrAddress = avrAddress;
}
@@ -72,9 +70,9 @@
protected final void disableArcTransmission() {
// Start Set ARC Transmission State action.
- SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(mService,
- mSourceAddress, mAvrAddress, false);
- mService.addAndStartAction(action);
+ SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(localDevice(),
+ mAvrAddress, false);
+ addAndStartAction(action);
}
@Override
diff --git a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
index 343aff7..55fb65a 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
@@ -31,18 +31,18 @@
*
* For more details look at {@link RequestArcAction#RequestArcAction}.
*/
- RequestArcInitiationAction(HdmiControlService service, int sourceAddress, int avrAddress) {
- super(service, sourceAddress, avrAddress);
+ RequestArcInitiationAction(HdmiCecLocalDevice source, int avrAddress) {
+ super(source, avrAddress);
}
@Override
boolean start() {
- HdmiCecMessage command = HdmiCecMessageBuilder.buildRequestArcInitiation(mSourceAddress,
- mAvrAddress);
+ HdmiCecMessage command = HdmiCecMessageBuilder.buildRequestArcInitiation(
+ getSourceAddress(), mAvrAddress);
sendCommand(command, new HdmiControlService.SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
- if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
+ if (error == HdmiConstants.SEND_RESULT_SUCCESS) {
mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE;
addTimer(mState, TIMEOUT_MS);
} else {
diff --git a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
index d4a35f8..62ca8f6 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
@@ -31,18 +31,18 @@
*
* @see RequestArcAction#RequestArcAction
*/
- RequestArcTerminationAction(HdmiControlService service, int sourceAddress, int avrAddress) {
- super(service, sourceAddress, avrAddress);
+ RequestArcTerminationAction(HdmiCecLocalDevice source, int avrAddress) {
+ super(source, avrAddress);
}
@Override
boolean start() {
HdmiCecMessage command =
- HdmiCecMessageBuilder.buildRequestArcTermination(mSourceAddress, mAvrAddress);
+ HdmiCecMessageBuilder.buildRequestArcTermination(getSourceAddress(), mAvrAddress);
sendCommand(command, new HdmiControlService.SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
- if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
+ if (error == HdmiConstants.SEND_RESULT_SUCCESS) {
mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE;
addTimer(mState, TIMEOUT_MS);
} else {
diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
new file mode 100644
index 0000000..2eec846
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
@@ -0,0 +1,233 @@
+/*
+ * 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.server.hdmi;
+
+import android.annotation.Nullable;
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
+/**
+ * Feature action for routing control. Exchanges routing-related commands with other devices
+ * to determine the new active source.
+ *
+ * <p>This action is initiated by various cases:
+ * <ul>
+ * <li> Manual TV input switching
+ * <li> Routing change of a CEC switch other than TV
+ * <li> New CEC device at the tail of the active routing path
+ * <li> Removed CEC device from the active routing path
+ * <li> Routing at CEC enable time
+ * </ul>
+ */
+final class RoutingControlAction extends FeatureAction {
+ private static final String TAG = "RoutingControlAction";
+
+ // State in which we wait for <Routing Information> to arrive. If timed out, we use the
+ // latest routing path to set the new active source.
+ private final static int STATE_WAIT_FOR_ROUTING_INFORMATION = 1;
+
+ // State in which we wait for <Report Power Status> in response to <Give Device Power Status>
+ // we have sent. If the response tells us the device power is on, we send <Set Stream Path>
+ // to make it the active source. Otherwise we do not send <Set Stream Path>, and possibly
+ // just show the blank screen.
+ private final static int STATE_WAIT_FOR_REPORT_POWER_STATUS = 2;
+
+ // Time out in millseconds used for <Routing Information>
+ private static final int TIMEOUT_ROUTING_INFORMATION_MS = 1000;
+
+ // Time out in milliseconds used for <Report Power Status>
+ private static final int TIMEOUT_REPORT_POWER_STATUS_MS = 1000;
+
+ @Nullable private final IHdmiControlCallback mCallback;
+
+ // The latest routing path. Updated by each <Routing Information> from CEC switches.
+ private int mCurrentRoutingPath;
+
+ RoutingControlAction(HdmiCecLocalDevice localDevice, int path, IHdmiControlCallback callback) {
+ super(localDevice);
+ mCallback = callback;
+ mCurrentRoutingPath = path;
+ }
+
+ @Override
+ public boolean start() {
+ mState = STATE_WAIT_FOR_ROUTING_INFORMATION;
+ addTimer(mState, TIMEOUT_ROUTING_INFORMATION_MS);
+ return true;
+ }
+
+ @Override
+ public boolean processCommand(HdmiCecMessage cmd) {
+ int opcode = cmd.getOpcode();
+ byte[] params = cmd.getParams();
+ if (mState == STATE_WAIT_FOR_ROUTING_INFORMATION
+ && opcode == HdmiCec.MESSAGE_ROUTING_INFORMATION) {
+ // Keep updating the physicalAddress as we receive <Routing Information>.
+ // If the routing path doesn't belong to the currently active one, we should
+ // ignore it since it might have come from other routing change sequence.
+ int routingPath = HdmiUtils.twoBytesToInt(params);
+ if (isInActiveRoutingPath(mCurrentRoutingPath, routingPath)) {
+ return true;
+ }
+ mCurrentRoutingPath = routingPath;
+ // Stop possible previous routing change sequence if in progress.
+ removeAction(RoutingControlAction.class);
+ addTimer(mState, TIMEOUT_ROUTING_INFORMATION_MS);
+ return true;
+ } else if (mState == STATE_WAIT_FOR_REPORT_POWER_STATUS
+ && opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS) {
+ handleReportPowerStatus(cmd.getParams()[0]);
+ return true;
+ }
+ return false;
+ }
+
+ private void handleReportPowerStatus(int devicePowerStatus) {
+ int tvPowerStatus = getTvPowerStatus();
+ if (isPowerStatusOnOrTransientToOn(tvPowerStatus)) {
+ if (isPowerStatusOnOrTransientToOn(devicePowerStatus)) {
+ sendSetStreamPath();
+ } else {
+ // The whole action should be stopped here if the device is in standby mode.
+ // We don't attempt to wake it up by sending <Set Stream Path>.
+ }
+ invokeCallback(HdmiCec.RESULT_SUCCESS);
+ finish();
+ } else {
+ // TV is going into standby mode.
+ // TODO: Figure out what to do.
+ }
+ }
+
+ private int getTvPowerStatus() {
+ // TODO: Obtain TV power status.
+ return HdmiCec.POWER_STATUS_ON;
+ }
+
+ private static boolean isPowerStatusOnOrTransientToOn(int status) {
+ return status == HdmiCec.POWER_STATUS_ON || status == HdmiCec.POWER_STATUS_TRANSIENT_TO_ON;
+ }
+
+ private void sendSetStreamPath() {
+ sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(getSourceAddress(),
+ mCurrentRoutingPath));
+ }
+
+ private static boolean isInActiveRoutingPath(int activePath, int newPath) {
+ // Check each nibble of the currently active path and the new path till the position
+ // where the active nibble is not zero. For (activePath, newPath),
+ // (1.1.0.0, 1.0.0.0) -> true, new path is a parent
+ // (1.2.1.0, 1.2.1.2) -> true, new path is a descendant
+ // (1.1.0.0, 1.2.0.0) -> false, new path is a sibling
+ // (1.0.0.0, 2.0.0.0) -> false, in a completely different path
+ for (int i = 12; i >= 0; i -= 4) {
+ int nibbleActive = (activePath >> i) & 0xF;
+ if (nibbleActive == 0) {
+ break;
+ }
+ int nibbleNew = (newPath >> i) & 0xF;
+ if (nibbleNew == 0) {
+ break;
+ }
+ if (nibbleActive != nibbleNew) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void handleTimerEvent(int timeoutState) {
+ if (mState != timeoutState || mState == STATE_NONE) {
+ Slog.w("CEC", "Timer in a wrong state. Ignored.");
+ return;
+ }
+ switch (timeoutState) {
+ case STATE_WAIT_FOR_ROUTING_INFORMATION:
+ HdmiCecDeviceInfo device = tv().getDeviceInfoByPath(mCurrentRoutingPath);
+ if (device == null) {
+ maybeChangeActiveInput(tv().pathToPortId(mCurrentRoutingPath));
+ } else {
+ // TODO: Also check followings and then proceed:
+ // if routing change was neither triggered by TV at CEC enable time, nor
+ // at the detection of new device at the end of the active routing path, nor
+ // by TV power on with HDMI input as the active signal source.
+ int deviceLogicalAddress = device.getLogicalAddress();
+ queryDevicePowerStatus(deviceLogicalAddress, new SendMessageCallback() {
+ @Override
+ public void onSendCompleted(int error) {
+ handlDevicePowerStatusAckResult(error == HdmiCec.RESULT_SUCCESS);
+ }
+ });
+ }
+ return;
+ case STATE_WAIT_FOR_REPORT_POWER_STATUS:
+ int tvPowerStatus = getTvPowerStatus();
+ if (isPowerStatusOnOrTransientToOn(tvPowerStatus)) {
+ if (!maybeChangeActiveInput(localDevice().pathToPortId(mCurrentRoutingPath))) {
+ sendSetStreamPath();
+ }
+ }
+ invokeCallback(HdmiCec.RESULT_SUCCESS);
+ finish();
+ return;
+ }
+ }
+
+ // Called whenever an HDMI input of the TV shall become the active input.
+ private boolean maybeChangeActiveInput(int path) {
+ if (localDevice().getActiveInput() == localDevice().pathToPortId(path)) {
+ return false;
+ }
+ // TODO: Remember the currently active input
+ // if PAP/PIP is active, move the focus to the right window, otherwise switch
+ // the port.
+ // Show the OSD input change banner.
+ return true;
+ }
+
+ private void queryDevicePowerStatus(int address, SendMessageCallback callback) {
+ sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), address),
+ callback);
+ }
+
+ private void handlDevicePowerStatusAckResult(boolean acked) {
+ if (acked) {
+ mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
+ addTimer(mState, TIMEOUT_REPORT_POWER_STATUS_MS);
+ } else {
+ maybeChangeActiveInput(localDevice().pathToPortId(mCurrentRoutingPath));
+ }
+ }
+
+ private void invokeCallback(int result) {
+ if (mCallback == null) {
+ return;
+ }
+ try {
+ mCallback.onComplete(result);
+ } catch (RemoteException e) {
+ // Do nothing.
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/SendKeyAction.java b/services/core/java/com/android/server/hdmi/SendKeyAction.java
new file mode 100644
index 0000000..c3078a2
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/SendKeyAction.java
@@ -0,0 +1,149 @@
+/*
+ * 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.server.hdmi;
+
+import android.hardware.hdmi.HdmiCecMessage;
+import android.util.Slog;
+import android.view.KeyEvent;
+
+/**
+ * Feature action that transmits remote control key command (User Control Press/
+ * User Control Release) to CEC bus.
+ *
+ * <p>This action is created when a new key event is passed to CEC service. It optionally
+ * does key repeat (a.k.a. press-and-hold) operation until it receives a key release event.
+ * If another key press event is received before the key in use is released, CEC service
+ * does not create a new action but recycles the current one by updating the key used
+ * for press-and-hold operation.
+ *
+ * <p>Package-private, accessed by {@link HdmiControlService} only.
+ */
+final class SendKeyAction extends FeatureAction {
+ private static final String TAG = "SendKeyAction";
+
+ // State in which the action is at work. The state is set in {@link #start()} and
+ // persists throughout the process till it is set back to {@code STATE_NONE} at the end.
+ private static final int STATE_PROCESSING_KEYCODE = 1;
+
+ // IRT(Initiator Repetition Time) in millisecond as recommended in the standard.
+ // Outgoing UCP commands, when in 'Press and Hold' mode, should be this much apart
+ // from the adjacent one so as not to place unnecessarily heavy load on the CEC line.
+ // TODO: This value might need tweaking per product basis. Consider putting it
+ // in config.xml to allow customization.
+ private static final int IRT_MS = 450;
+
+ // Logical address of the device to which the UCP/UCP commands are sent.
+ private final int mTargetAddress;
+
+ // The key code of the last key press event the action is passed via processKeyEvent.
+ private int mLastKeyCode;
+
+ /**
+ * Constructor.
+ *
+ * @param source {@link HdmiCecLocalDevice} instance
+ * @param targetAddress logical address of the device to send the keys to
+ * @param keyCode remote control key code as defined in {@link KeyEvent}
+ */
+ SendKeyAction(HdmiCecLocalDevice source, int targetAddress, int keyCode) {
+ super(source);
+ mTargetAddress = targetAddress;
+ mLastKeyCode = keyCode;
+ }
+
+ @Override
+ public boolean start() {
+ sendKeyDown(mLastKeyCode);
+ mState = STATE_PROCESSING_KEYCODE;
+ addTimer(mState, IRT_MS);
+ return true;
+ }
+
+ /**
+ * Called when a key event should be handled for the action.
+ *
+ * @param keyCode key code of {@link KeyEvent} object
+ * @param isPressed true if the key event is of {@link KeyEvent#ACTION_DOWN}
+ * @param param additional parameter that comes with the key event
+ */
+ void processKeyEvent(int keyCode, boolean isPressed) {
+ if (mState != STATE_PROCESSING_KEYCODE) {
+ Slog.w(TAG, "Not in a valid state");
+ return;
+ }
+ // A new key press event that comes in with a key code different from the last
+ // one sets becomes a new key code to be used for press-and-hold operation.
+ // Removes any pending timer and starts a new timer for itself.
+ // Key release event indicates that the action shall be finished. Send UCR
+ // command and terminate the action. Other release events are ignored.
+ if (isPressed) {
+ if (keyCode != mLastKeyCode) {
+ mActionTimer.clearTimerMessage();
+ sendKeyDown(keyCode);
+ addTimer(mState, IRT_MS);
+ mLastKeyCode = keyCode;
+ }
+ } else {
+ if (keyCode == mLastKeyCode) {
+ sendKeyUp();
+ finish();
+ }
+ }
+ }
+
+ private void sendKeyDown(int keyCode) {
+ byte[] keyCodeAndParam = getCecKeyCodeAndParam(keyCode);
+ if (keyCodeAndParam == null) {
+ return;
+ }
+ sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(),
+ mTargetAddress, keyCodeAndParam));
+ }
+
+ private void sendKeyUp() {
+ sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(getSourceAddress(),
+ mTargetAddress));
+ }
+
+ @Override
+ public boolean processCommand(HdmiCecMessage cmd) {
+ // Send key action doesn't need any incoming CEC command, hence does not consume it.
+ return false;
+ }
+
+ @Override
+ public void handleTimerEvent(int state) {
+ // Timer event occurs every IRT_MS milliseconds to perform key-repeat (or press-and-hold)
+ // operation. If the last received key code is as same as the one with which the action
+ // is started, plus there was no key release event in last IRT_MS timeframe, send a UCP
+ // command and start another timer to schedule the next press-and-hold command.
+ if (mState != STATE_PROCESSING_KEYCODE) {
+ Slog.w(TAG, "Not in a valid state");
+ return;
+ }
+ sendKeyDown(mLastKeyCode);
+ addTimer(mState, IRT_MS);
+ }
+
+ // Converts the Android key code to corresponding CEC key code definition. Those CEC keys
+ // with additional parameters should be mapped from individual Android key code. 'Select
+ // Broadcast' with the parameter 'cable', for instance, shall have its counterpart such as
+ // KeyEvent.KEYCODE_TV_BROADCAST_CABLE.
+ // The return byte array contains both UI command (keycode) and optional parameter.
+ private byte[] getCecKeyCodeAndParam(int keyCode) {
+ return HdmiCecKeycode.androidKeyToCecKey(keyCode);
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
index d53d88d..cdedd6b 100644
--- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
+++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
@@ -39,14 +39,13 @@
/**
* @Constructor
*
- * @param service an instance of {@link HdmiControlService}
- * @param sourceAddress logical address to be used as source address
+ * @param source {@link HdmiCecLocalDevice} instance
* @param enabled whether to enable ARC Transmission channel
*/
- SetArcTransmissionStateAction(HdmiControlService service, int sourceAddress, int avrAddress,
+ SetArcTransmissionStateAction(HdmiCecLocalDevice source, int avrAddress,
boolean enabled) {
- super(service, sourceAddress);
- HdmiUtils.verifyAddressType(sourceAddress, HdmiCec.DEVICE_TV);
+ super(source);
+ HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV);
HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
mAvrAddress = avrAddress;
mEnabled = enabled;
@@ -65,11 +64,11 @@
private void sendReportArcInitiated() {
HdmiCecMessage command =
- HdmiCecMessageBuilder.buildReportArcInitiated(mSourceAddress, mAvrAddress);
+ HdmiCecMessageBuilder.buildReportArcInitiated(getSourceAddress(), mAvrAddress);
sendCommand(command, new HdmiControlService.SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
- if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
+ if (error == HdmiConstants.SEND_RESULT_SUCCESS) {
// Enable ARC status immediately after sending <Report Arc Initiated>.
// If AVR responds with <Feature Abort>, disable ARC status again.
// This is different from spec that says that turns ARC status to
@@ -93,14 +92,14 @@
}
private void setArcStatus(boolean enabled) {
- boolean wasEnabled = mService.setArcStatus(enabled);
+ boolean wasEnabled = tv().setArcStatus(enabled);
Slog.i(TAG, "Change arc status [old:" + wasEnabled + " ,new:" + enabled);
// If enabled before and set to "disabled" and send <Report Arc Terminated> to
// av reciever.
if (!enabled && wasEnabled) {
- sendCommand(
- HdmiCecMessageBuilder.buildReportArcTerminated(mSourceAddress, mAvrAddress));
+ sendCommand(HdmiCecMessageBuilder.buildReportArcTerminated(getSourceAddress(),
+ mAvrAddress));
}
}
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
index dde3342..e48b0dc 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -47,28 +47,27 @@
/**
* Constructor
*
- * @param service {@link HdmiControlService} instance
- * @param sourceAddress logical address of source device (TV or STB).
+ * @param source {@link HdmiCecLocalDevice} instance
* @param avrAddress logical address of AVR device
* @param targetStatus Whether to enable the system audio mode or not
* @throw IllegalArugmentException if device type of sourceAddress and avrAddress is invalid
*/
- SystemAudioAction(HdmiControlService service, int sourceAddress, int avrAddress,
- boolean targetStatus) {
- super(service, sourceAddress);
+ SystemAudioAction(HdmiCecLocalDevice source, int avrAddress, boolean targetStatus) {
+ super(source);
HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
mAvrLogicalAddress = avrAddress;
mTargetAudioStatus = targetStatus;
}
protected void sendSystemAudioModeRequest() {
- int avrPhysicalAddress = mService.getAvrDeviceInfo().getPhysicalAddress();
- HdmiCecMessage command = HdmiCecMessageBuilder.buildSystemAudioModeRequest(mSourceAddress,
+ int avrPhysicalAddress = tv().getAvrDeviceInfo().getPhysicalAddress();
+ HdmiCecMessage command = HdmiCecMessageBuilder.buildSystemAudioModeRequest(
+ getSourceAddress(),
mAvrLogicalAddress, avrPhysicalAddress, mTargetAudioStatus);
sendCommand(command, new HdmiControlService.SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
- if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
+ if (error == HdmiConstants.SEND_RESULT_SUCCESS) {
mState = STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE;
addTimer(mState, mTargetAudioStatus ? ON_TIMEOUT_MS : OFF_TIMEOUT_MS);
} else {
@@ -90,16 +89,16 @@
}
protected void setSystemAudioMode(boolean mode) {
- mService.setSystemAudioMode(mode);
+ tv().setSystemAudioMode(mode);
}
protected void sendGiveAudioStatus() {
- HdmiCecMessage command = HdmiCecMessageBuilder.buildGiveAudioStatus(mSourceAddress,
+ HdmiCecMessage command = HdmiCecMessageBuilder.buildGiveAudioStatus(getSourceAddress(),
mAvrLogicalAddress);
sendCommand(command, new HdmiControlService.SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
- if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
+ if (error == HdmiConstants.SEND_RESULT_SUCCESS) {
mState = STATE_WAIT_FOR_REPORT_AUDIO_STATUS;
addTimer(mState, TIMEOUT_MS);
} else {
@@ -112,7 +111,7 @@
private void handleSendGiveAudioStatusFailure() {
// TODO: Notify the failure status.
- int uiCommand = mService.getSystemAudioMode()
+ int uiCommand = tv().getSystemAudioMode()
? HdmiConstants.UI_COMMAND_RESTORE_VOLUME_FUNCTION // SystemAudioMode: ON
: HdmiConstants.UI_COMMAND_MUTE_FUNCTION; // SystemAudioMode: OFF
sendUserControlPressedAndReleased(uiCommand);
@@ -121,9 +120,9 @@
private void sendUserControlPressedAndReleased(int uiCommand) {
sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(
- mSourceAddress, mAvrLogicalAddress, uiCommand));
+ getSourceAddress(), mAvrLogicalAddress, uiCommand));
sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
- mSourceAddress, mAvrLogicalAddress));
+ getSourceAddress(), mAvrLogicalAddress));
}
@Override
@@ -158,7 +157,7 @@
if (params.length > 0) {
boolean mute = (params[0] & 0x80) == 0x80;
int volume = params[0] & 0x7F;
- mService.setAudioStatus(mute, volume);
+ tv().setAudioStatus(mute, volume);
if (mTargetAudioStatus && mute || !mTargetAudioStatus && !mute) {
// Toggle AVR's mute status to match with the system audio status.
sendUserControlPressedAndReleased(HdmiConstants.UI_COMMAND_MUTE);
@@ -171,8 +170,8 @@
}
protected void removeSystemAudioActionInProgress() {
- mService.removeActionExcept(SystemAudioActionFromTv.class, this);
- mService.removeActionExcept(SystemAudioActionFromAvr.class, this);
+ removeActionExcept(SystemAudioActionFromTv.class, this);
+ removeActionExcept(SystemAudioActionFromAvr.class, this);
}
@Override
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
index c5eb44b..3907b71 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromAvr.java
@@ -25,16 +25,15 @@
/**
* Constructor
*
- * @param service {@link HdmiControlService} instance
- * @param tvAddress logical address of TV device
+ * @param source {@link HdmiCecLocalDevice} instance
* @param avrAddress logical address of AVR device
* @param targetStatus Whether to enable the system audio mode or not
* @throw IllegalArugmentException if device type of tvAddress and avrAddress is invalid
*/
- SystemAudioActionFromAvr(HdmiControlService service, int tvAddress, int avrAddress,
+ SystemAudioActionFromAvr(HdmiCecLocalDevice source, int avrAddress,
boolean targetStatus) {
- super(service, tvAddress, avrAddress, targetStatus);
- HdmiUtils.verifyAddressType(tvAddress, HdmiCec.DEVICE_TV);
+ super(source, avrAddress, targetStatus);
+ HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV);
}
@Override
@@ -45,13 +44,13 @@
}
private void handleSystemAudioActionFromAvr() {
- if (mTargetAudioStatus == mService.getSystemAudioMode()) {
+ if (mTargetAudioStatus == tv().getSystemAudioMode()) {
finish();
return;
}
- if (mService.isInPresetInstallationMode()) {
+ if (tv().isInPresetInstallationMode()) {
sendCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(
- mSourceAddress, mAvrLogicalAddress,
+ getSourceAddress(), mAvrLogicalAddress,
HdmiCec.MESSAGE_SET_SYSTEM_AUDIO_MODE, HdmiConstants.ABORT_REFUSED));
mTargetAudioStatus = false;
sendSystemAudioModeRequest();
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
index 9994de6..e0c4ff4 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioActionFromTv.java
@@ -26,16 +26,15 @@
/**
* Constructor
*
- * @param service {@link HdmiControlService} instance
- * @param tvAddress logical address of TV device
+ * @param sourceAddress {@link HdmiCecLocalDevice} instance
* @param avrAddress logical address of AVR device
* @param targetStatus Whether to enable the system audio mode or not
* @throw IllegalArugmentException if device type of tvAddress is invalid
*/
- SystemAudioActionFromTv(HdmiControlService service, int tvAddress, int avrAddress,
+ SystemAudioActionFromTv(HdmiCecLocalDevice sourceAddress, int avrAddress,
boolean targetStatus) {
- super(service, tvAddress, avrAddress, targetStatus);
- HdmiUtils.verifyAddressType(tvAddress, HdmiCec.DEVICE_TV);
+ super(sourceAddress, avrAddress, targetStatus);
+ HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCec.DEVICE_TV);
}
@Override
diff --git a/services/core/java/com/android/server/hdmi/VendorSpecificAction.java b/services/core/java/com/android/server/hdmi/VendorSpecificAction.java
new file mode 100644
index 0000000..c954b50
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/VendorSpecificAction.java
@@ -0,0 +1,54 @@
+package com.android.server.hdmi;
+
+import android.hardware.hdmi.HdmiCecMessage;
+
+/**
+ * Handles vendor-specific commands that require a sequence of command exchange,
+ * or need to manage some states to complete the processing.
+ */
+public class VendorSpecificAction extends FeatureAction {
+
+ // Sample state this action can be in.
+ private static final int STATE_1 = 1;
+ private static final int STATE_2 = 2;
+
+ VendorSpecificAction(HdmiCecLocalDevice source) {
+ super(source);
+ // Modify the constructor if additional arguments are necessary.
+ }
+
+ @Override
+ boolean start() {
+ // Do initialization step and update the state accordingly here.
+ mState = STATE_1;
+ addTimer(STATE_1, TIMEOUT_MS);
+ return true;
+ }
+
+ @Override
+ boolean processCommand(HdmiCecMessage cmd) {
+ // Returns true if the command was consumed. Otherwise return false for other
+ // actions in progress can be given its turn to process it.
+ return false;
+ }
+
+ @Override
+ void handleTimerEvent(int state) {
+ // Ignore the timer event if the current state and the state this event should be
+ // handled in are different. Could be an outdated event which should have been cleared by
+ // calling {@code mActionTimer.clearTimerMessage()}.
+ if (mState != state) {
+ return;
+ }
+
+ switch (state) {
+ case STATE_1:
+ mState = STATE_2;
+ addTimer(STATE_2, TIMEOUT_MS);
+ break;
+ case STATE_2:
+ finish();
+ break;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/task/TaskCompletedListener.java b/services/core/java/com/android/server/job/JobCompletedListener.java
similarity index 62%
rename from services/core/java/com/android/server/task/TaskCompletedListener.java
rename to services/core/java/com/android/server/job/JobCompletedListener.java
index c53f5ca..a7af9cd 100644
--- a/services/core/java/com/android/server/task/TaskCompletedListener.java
+++ b/services/core/java/com/android/server/job/JobCompletedListener.java
@@ -14,19 +14,19 @@
* limitations under the License
*/
-package com.android.server.task;
+package com.android.server.job;
-import com.android.server.task.controllers.TaskStatus;
+import com.android.server.job.controllers.JobStatus;
/**
- * Used for communication between {@link com.android.server.task.TaskServiceContext} and the
- * {@link com.android.server.task.TaskManagerService}.
+ * Used for communication between {@link com.android.server.job.JobServiceContext} and the
+ * {@link com.android.server.job.JobSchedulerService}.
*/
-public interface TaskCompletedListener {
+public interface JobCompletedListener {
/**
- * Callback for when a task is completed.
- * @param needsReschedule Whether the implementing class should reschedule this task.
+ * Callback for when a job is completed.
+ * @param needsReschedule Whether the implementing class should reschedule this job.
*/
- public void onTaskCompleted(TaskStatus taskStatus, boolean needsReschedule);
+ public void onJobCompleted(JobStatus jobStatus, boolean needsReschedule);
}
diff --git a/services/core/java/com/android/server/task/TaskMapReadFinishedListener.java b/services/core/java/com/android/server/job/JobMapReadFinishedListener.java
similarity index 68%
rename from services/core/java/com/android/server/task/TaskMapReadFinishedListener.java
rename to services/core/java/com/android/server/job/JobMapReadFinishedListener.java
index c68d8db..f3e77e6 100644
--- a/services/core/java/com/android/server/task/TaskMapReadFinishedListener.java
+++ b/services/core/java/com/android/server/job/JobMapReadFinishedListener.java
@@ -14,21 +14,21 @@
* limitations under the License
*/
-package com.android.server.task;
+package com.android.server.job;
import java.util.List;
-import com.android.server.task.controllers.TaskStatus;
+import com.android.server.job.controllers.JobStatus;
/**
- * Callback definition for I/O thread to let the TaskManagerService know when
+ * Callback definition for I/O thread to let the JobManagerService know when
* I/O read has completed. Done this way so we don't stall the main thread on
* boot.
*/
-public interface TaskMapReadFinishedListener {
+public interface JobMapReadFinishedListener {
/**
- * Called by the {@link TaskStore} at boot, when the disk read is finished.
+ * Called by the {@link JobStore} at boot, when the disk read is finished.
*/
- public void onTaskMapReadFinished(List<TaskStatus> tasks);
+ public void onJobMapReadFinished(List<JobStatus> jobs);
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
new file mode 100644
index 0000000..0e9a9cc
--- /dev/null
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -0,0 +1,764 @@
+/*
+ * 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.server.job;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.app.job.IJobScheduler;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.server.job.controllers.BatteryController;
+import com.android.server.job.controllers.ConnectivityController;
+import com.android.server.job.controllers.IdleController;
+import com.android.server.job.controllers.JobStatus;
+import com.android.server.job.controllers.StateController;
+import com.android.server.job.controllers.TimeController;
+
+import java.util.LinkedList;
+
+/**
+ * Responsible for taking jobs representing work to be performed by a client app, and determining
+ * based on the criteria specified when that job should be run against the client application's
+ * endpoint.
+ * Implements logic for scheduling, and rescheduling jobs. The JobSchedulerService knows nothing
+ * about constraints, or the state of active jobs. It receives callbacks from the various
+ * controllers and completed jobs and operates accordingly.
+ *
+ * Note on locking: Any operations that manipulate {@link #mJobs} need to lock on that object.
+ * Any function with the suffix 'Locked' also needs to lock on {@link #mJobs}.
+ * @hide
+ */
+public class JobSchedulerService extends com.android.server.SystemService
+ implements StateChangedListener, JobCompletedListener, JobMapReadFinishedListener {
+ // TODO: Switch this off for final version.
+ static final boolean DEBUG = true;
+ /** The number of concurrent jobs we run at one time. */
+ private static final int MAX_JOB_CONTEXTS_COUNT = 3;
+ static final String TAG = "JobManagerService";
+ /** Master list of jobs. */
+ private final JobStore mJobs;
+
+ static final int MSG_JOB_EXPIRED = 0;
+ static final int MSG_CHECK_JOB = 1;
+
+ // Policy constants
+ /**
+ * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things
+ * early.
+ */
+ private static final int MIN_IDLE_COUNT = 1;
+ /**
+ * Minimum # of connectivity jobs that must be ready in order to force the JMS to schedule
+ * things early.
+ */
+ private static final int MIN_CONNECTIVITY_COUNT = 2;
+ /**
+ * Minimum # of jobs (with no particular constraints) for which the JMS will be happy running
+ * some work early.
+ */
+ private static final int MIN_READY_JOBS_COUNT = 4;
+
+ /**
+ * Track Services that have currently active or pending jobs. The index is provided by
+ * {@link JobStatus#getServiceToken()}
+ */
+ private final List<JobServiceContext> mActiveServices = new LinkedList<JobServiceContext>();
+ /** List of controllers that will notify this service of updates to jobs. */
+ private List<StateController> mControllers;
+ /**
+ * Queue of pending jobs. The JobServiceContext class will receive jobs from this list
+ * when ready to execute them.
+ */
+ private final LinkedList<JobStatus> mPendingJobs = new LinkedList<JobStatus>();
+
+ private final JobHandler mHandler;
+ private final JobSchedulerStub mJobSchedulerStub;
+ /**
+ * 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.
+ */
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Slog.d(TAG, "Receieved: " + intent.getAction());
+ if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+ int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ if (DEBUG) {
+ Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
+ }
+ cancelJobsForUid(uidRemoved);
+ } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+ if (DEBUG) {
+ Slog.d(TAG, "Removing jobs for user: " + userId);
+ }
+ cancelJobsForUser(userId);
+ }
+ }
+ };
+
+ /**
+ * Entry point from client to schedule the provided job.
+ * This cancels the job if it's already been scheduled, and replaces it with the one provided.
+ * @param job JobInfo object containing execution parameters
+ * @param uId The package identifier of the application this job is for.
+ * @param canPersistJob Whether or not the client has the appropriate permissions for
+ * persisting this job.
+ * @return Result of this operation. See <code>JobScheduler#RESULT_*</code> return codes.
+ */
+ public int schedule(JobInfo job, int uId, boolean canPersistJob) {
+ JobStatus jobStatus = new JobStatus(job, uId, canPersistJob);
+ cancelJob(uId, job.getId());
+ startTrackingJob(jobStatus);
+ return JobScheduler.RESULT_SUCCESS;
+ }
+
+ public List<JobInfo> getPendingJobs(int uid) {
+ ArrayList<JobInfo> outList = new ArrayList<JobInfo>();
+ synchronized (mJobs) {
+ for (JobStatus job : mJobs.getJobs()) {
+ if (job.getUid() == uid) {
+ outList.add(job.getJob());
+ }
+ }
+ }
+ return outList;
+ }
+
+ private void cancelJobsForUser(int userHandle) {
+ synchronized (mJobs) {
+ List<JobStatus> jobsForUser = mJobs.getJobsByUser(userHandle);
+ for (JobStatus toRemove : jobsForUser) {
+ if (DEBUG) {
+ Slog.d(TAG, "Cancelling: " + toRemove);
+ }
+ cancelJobLocked(toRemove);
+ }
+ }
+ }
+
+ /**
+ * Entry point from client to cancel all jobs originating from their uid.
+ * This will remove the job from the master list, and cancel the job if it was staged for
+ * execution or being executed.
+ * @param uid To check against for removal of a job.
+ */
+ public void cancelJobsForUid(int uid) {
+ // Remove from master list.
+ synchronized (mJobs) {
+ List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
+ for (JobStatus toRemove : jobsForUid) {
+ if (DEBUG) {
+ Slog.d(TAG, "Cancelling: " + toRemove);
+ }
+ cancelJobLocked(toRemove);
+ }
+ }
+ }
+
+ /**
+ * Entry point from client to cancel the job corresponding to the jobId provided.
+ * This will remove the job from the master list, and cancel the job if it was staged for
+ * execution or being executed.
+ * @param uid Uid of the calling client.
+ * @param jobId Id of the job, provided at schedule-time.
+ */
+ public void cancelJob(int uid, int jobId) {
+ JobStatus toCancel;
+ synchronized (mJobs) {
+ toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
+ if (toCancel != null) {
+ cancelJobLocked(toCancel);
+ }
+ }
+ }
+
+ private void cancelJobLocked(JobStatus cancelled) {
+ // Remove from store.
+ stopTrackingJob(cancelled);
+ // Remove from pending queue.
+ mPendingJobs.remove(cancelled);
+ // Cancel if running.
+ stopJobOnServiceContextLocked(cancelled);
+ }
+
+ /**
+ * Initializes the system service.
+ * <p>
+ * Subclasses must define a single argument constructor that accepts the context
+ * and passes it to super.
+ * </p>
+ *
+ * @param context The system server context.
+ */
+ public JobSchedulerService(Context context) {
+ super(context);
+ // Create the controllers.
+ mControllers = new LinkedList<StateController>();
+ mControllers.add(ConnectivityController.get(this));
+ mControllers.add(TimeController.get(this));
+ mControllers.add(IdleController.get(this));
+ mControllers.add(BatteryController.get(this));
+
+ mHandler = new JobHandler(context.getMainLooper());
+ mJobSchedulerStub = new JobSchedulerStub();
+ // Create the "runners".
+ for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
+ mActiveServices.add(
+ new JobServiceContext(this, context.getMainLooper()));
+ }
+ mJobs = JobStore.initAndGet(this);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.JOB_SCHEDULER_SERVICE, mJobSchedulerStub);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (PHASE_SYSTEM_SERVICES_READY == phase) {
+ // Register br for package removals and user removals.
+ final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ getContext().registerReceiverAsUser(
+ mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+ final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
+ getContext().registerReceiverAsUser(
+ mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
+ }
+ }
+
+ /**
+ * Called when we have a job status object that we need to insert in our
+ * {@link com.android.server.job.JobStore}, and make sure all the relevant controllers know
+ * about.
+ */
+ private void startTrackingJob(JobStatus jobStatus) {
+ boolean update;
+ synchronized (mJobs) {
+ update = mJobs.add(jobStatus);
+ }
+ for (StateController controller : mControllers) {
+ if (update) {
+ controller.maybeStopTrackingJob(jobStatus);
+ }
+ controller.maybeStartTrackingJob(jobStatus);
+ }
+ }
+
+ /**
+ * Called when we want to remove a JobStatus object that we've finished executing. Returns the
+ * object removed.
+ */
+ private boolean stopTrackingJob(JobStatus jobStatus) {
+ boolean removed;
+ synchronized (mJobs) {
+ // Remove from store as well as controllers.
+ removed = mJobs.remove(jobStatus);
+ }
+ if (removed) {
+ for (StateController controller : mControllers) {
+ controller.maybeStopTrackingJob(jobStatus);
+ }
+ }
+ return removed;
+ }
+
+ private boolean stopJobOnServiceContextLocked(JobStatus job) {
+ for (JobServiceContext jsc : mActiveServices) {
+ final JobStatus executing = jsc.getRunningJob();
+ if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
+ jsc.cancelExecutingJob();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param job JobStatus we are querying against.
+ * @return Whether or not the job represented by the status object is currently being run or
+ * is pending.
+ */
+ private boolean isCurrentlyActiveLocked(JobStatus job) {
+ for (JobServiceContext serviceContext : mActiveServices) {
+ final JobStatus running = serviceContext.getRunningJob();
+ if (running != null && running.matches(job.getUid(), job.getJobId())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A job is rescheduled with exponential back-off if the client requests this from their
+ * execution logic.
+ * A caveat is for idle-mode jobs, for which the idle-mode constraint will usurp the
+ * timeliness of the reschedule. For an idle-mode job, no deadline is given.
+ * @param failureToReschedule Provided job status that we will reschedule.
+ * @return A newly instantiated JobStatus with the same constraints as the last job except
+ * with adjusted timing constraints.
+ */
+ private JobStatus getRescheduleJobForFailure(JobStatus failureToReschedule) {
+ final long elapsedNowMillis = SystemClock.elapsedRealtime();
+ final JobInfo job = failureToReschedule.getJob();
+
+ final long initialBackoffMillis = job.getInitialBackoffMillis();
+ final int backoffAttempt = failureToReschedule.getNumFailures() + 1;
+ long newEarliestRuntimeElapsed = elapsedNowMillis;
+
+ switch (job.getBackoffPolicy()) {
+ case JobInfo.BackoffPolicy.LINEAR:
+ newEarliestRuntimeElapsed += initialBackoffMillis * backoffAttempt;
+ break;
+ default:
+ if (DEBUG) {
+ Slog.v(TAG, "Unrecognised back-off policy, defaulting to exponential.");
+ }
+ case JobInfo.BackoffPolicy.EXPONENTIAL:
+ newEarliestRuntimeElapsed +=
+ Math.pow(initialBackoffMillis * 0.001, backoffAttempt) * 1000;
+ break;
+ }
+ newEarliestRuntimeElapsed =
+ Math.min(newEarliestRuntimeElapsed, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
+ return new JobStatus(failureToReschedule, newEarliestRuntimeElapsed,
+ JobStatus.NO_LATEST_RUNTIME, backoffAttempt);
+ }
+
+ /**
+ * Called after a periodic has executed so we can to re-add it. We take the last execution time
+ * of the job to be the time of completion (i.e. the time at which this function is called).
+ * This could be inaccurate b/c the job can run for as long as
+ * {@link com.android.server.job.JobServiceContext#EXECUTING_TIMESLICE_MILLIS}, but will lead
+ * to underscheduling at least, rather than if we had taken the last execution time to be the
+ * start of the execution.
+ * @return A new job representing the execution criteria for this instantiation of the
+ * recurring job.
+ */
+ private JobStatus getRescheduleJobForPeriodic(JobStatus periodicToReschedule) {
+ final long elapsedNow = SystemClock.elapsedRealtime();
+ // Compute how much of the period is remaining.
+ long runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0);
+ long newEarliestRunTimeElapsed = elapsedNow + runEarly;
+ long period = periodicToReschedule.getJob().getIntervalMillis();
+ long newLatestRuntimeElapsed = newEarliestRunTimeElapsed + period;
+
+ if (DEBUG) {
+ Slog.v(TAG, "Rescheduling executed periodic. New execution window [" +
+ newEarliestRunTimeElapsed/1000 + ", " + newLatestRuntimeElapsed/1000 + "]s");
+ }
+ return new JobStatus(periodicToReschedule, newEarliestRunTimeElapsed,
+ newLatestRuntimeElapsed, 0 /* backoffAttempt */);
+ }
+
+ // JobCompletedListener implementations.
+
+ /**
+ * A job just finished executing. We fetch the
+ * {@link com.android.server.job.controllers.JobStatus} from the store and depending on
+ * whether we want to reschedule we readd it to the controllers.
+ * @param jobStatus Completed job.
+ * @param needsReschedule Whether the implementing class should reschedule this job.
+ */
+ @Override
+ public void onJobCompleted(JobStatus jobStatus, boolean needsReschedule) {
+ if (DEBUG) {
+ Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
+ }
+ if (!stopTrackingJob(jobStatus)) {
+ if (DEBUG) {
+ Slog.e(TAG, "Error removing job: could not find job to remove. Was job " +
+ "removed while executing?");
+ }
+ return;
+ }
+ if (needsReschedule) {
+ JobStatus rescheduled = getRescheduleJobForFailure(jobStatus);
+ startTrackingJob(rescheduled);
+ } else if (jobStatus.getJob().isPeriodic()) {
+ JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
+ startTrackingJob(rescheduledPeriodic);
+ }
+ mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
+ }
+
+ // StateChangedListener implementations.
+
+ /**
+ * Off-board work to our handler thread as quickly as possible, b/c this call is probably being
+ * made on the main thread.
+ * For now this takes the job and if it's ready to run it will run it. In future we might not
+ * provide the job, so that the StateChangedListener has to run through its list of jobs to
+ * see which are ready. This will further decouple the controllers from the execution logic.
+ */
+ @Override
+ public void onControllerStateChanged() {
+ // Post a message to to run through the list of jobs and start/stop any that are eligible.
+ mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
+ }
+
+ @Override
+ public void onRunJobNow(JobStatus jobStatus) {
+ mHandler.obtainMessage(MSG_JOB_EXPIRED, jobStatus).sendToTarget();
+ }
+
+ /**
+ * Disk I/O is finished, take the list of jobs we read from disk and add them to our
+ * {@link JobStore}.
+ * This is run on the {@link com.android.server.IoThread} instance, which is a separate thread,
+ * and is called once at boot.
+ */
+ @Override
+ public void onJobMapReadFinished(List<JobStatus> jobs) {
+ synchronized (mJobs) {
+ for (JobStatus js : jobs) {
+ if (mJobs.containsJobIdForUid(js.getJobId(), js.getUid())) {
+ // An app with BOOT_COMPLETED *might* have decided to reschedule their job, in
+ // the same amount of time it took us to read it from disk. If this is the case
+ // we leave it be.
+ continue;
+ }
+ startTrackingJob(js);
+ }
+ }
+ }
+
+ private class JobHandler extends Handler {
+
+ public JobHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_JOB_EXPIRED:
+ synchronized (mJobs) {
+ JobStatus runNow = (JobStatus) message.obj;
+ if (!mPendingJobs.contains(runNow)) {
+ mPendingJobs.add(runNow);
+ }
+ }
+ queueReadyJobsForExecutionH();
+ break;
+ case MSG_CHECK_JOB:
+ // Check the list of jobs and run some of them if we feel inclined.
+ maybeQueueReadyJobsForExecutionH();
+ break;
+ }
+ maybeRunPendingJobsH();
+ // Don't remove JOB_EXPIRED in case one came along while processing the queue.
+ removeMessages(MSG_CHECK_JOB);
+ }
+
+ /**
+ * Run through list of jobs and execute all possible - at least one is expired so we do
+ * as many as we can.
+ */
+ private void queueReadyJobsForExecutionH() {
+ synchronized (mJobs) {
+ for (JobStatus job : mJobs.getJobs()) {
+ if (isReadyToBeExecutedLocked(job)) {
+ mPendingJobs.add(job);
+ } else if (isReadyToBeCancelledLocked(job)) {
+ stopJobOnServiceContextLocked(job);
+ }
+ }
+ }
+ }
+
+ /**
+ * The state of at least one job has changed. Here is where we could enforce various
+ * policies on when we want to execute jobs.
+ * Right now the policy is such:
+ * If >1 of the ready jobs is idle mode we send all of them off
+ * if more than 2 network connectivity jobs are ready we send them all off.
+ * If more than 4 jobs total are ready we send them all off.
+ * TODO: It would be nice to consolidate these sort of high-level policies somewhere.
+ */
+ private void maybeQueueReadyJobsForExecutionH() {
+ synchronized (mJobs) {
+ int idleCount = 0;
+ int backoffCount = 0;
+ int connectivityCount = 0;
+ List<JobStatus> runnableJobs = new ArrayList<JobStatus>();
+ for (JobStatus job : mJobs.getJobs()) {
+ if (isReadyToBeExecutedLocked(job)) {
+ if (job.getNumFailures() > 0) {
+ backoffCount++;
+ }
+ if (job.hasIdleConstraint()) {
+ idleCount++;
+ }
+ if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint()) {
+ connectivityCount++;
+ }
+ runnableJobs.add(job);
+ } else if (isReadyToBeCancelledLocked(job)) {
+ stopJobOnServiceContextLocked(job);
+ }
+ }
+ if (backoffCount > 0 || idleCount >= MIN_IDLE_COUNT ||
+ connectivityCount >= MIN_CONNECTIVITY_COUNT ||
+ runnableJobs.size() >= MIN_READY_JOBS_COUNT) {
+ for (JobStatus job : runnableJobs) {
+ mPendingJobs.add(job);
+ }
+ }
+ }
+ }
+
+ /**
+ * Criteria for moving a job into the pending queue:
+ * - It's ready.
+ * - It's not pending.
+ * - It's not already running on a JSC.
+ */
+ private boolean isReadyToBeExecutedLocked(JobStatus job) {
+ return job.isReady() && !mPendingJobs.contains(job) && !isCurrentlyActiveLocked(job);
+ }
+
+ /**
+ * Criteria for cancelling an active job:
+ * - It's not ready
+ * - It's running on a JSC.
+ */
+ private boolean isReadyToBeCancelledLocked(JobStatus job) {
+ return !job.isReady() && isCurrentlyActiveLocked(job);
+ }
+
+ /**
+ * Reconcile jobs in the pending queue against available execution contexts.
+ * A controller can force a job into the pending queue even if it's already running, but
+ * here is where we decide whether to actually execute it.
+ */
+ private void maybeRunPendingJobsH() {
+ synchronized (mJobs) {
+ Iterator<JobStatus> it = mPendingJobs.iterator();
+ while (it.hasNext()) {
+ JobStatus nextPending = it.next();
+ JobServiceContext availableContext = null;
+ for (JobServiceContext jsc : mActiveServices) {
+ final JobStatus running = jsc.getRunningJob();
+ if (running != null && running.matches(nextPending.getUid(),
+ nextPending.getJobId())) {
+ // Already running this tId for this uId, skip.
+ availableContext = null;
+ break;
+ }
+ if (jsc.isAvailable()) {
+ availableContext = jsc;
+ }
+ }
+ if (availableContext != null) {
+ if (!availableContext.executeRunnableJob(nextPending)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Error executing " + nextPending);
+ }
+ mJobs.remove(nextPending);
+ }
+ it.remove();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Binder stub trampoline implementation
+ */
+ final class JobSchedulerStub extends IJobScheduler.Stub {
+ /** Cache determination of whether a given app can persist jobs
+ * key is uid of the calling app; value is undetermined/true/false
+ */
+ private final SparseArray<Boolean> mPersistCache = new SparseArray<Boolean>();
+
+ // Enforce that only the app itself (or shared uid participant) can schedule a
+ // job that runs one of the app's services, as well as verifying that the
+ // named service properly requires the BIND_JOB_SERVICE permission
+ private void enforceValidJobRequest(int uid, JobInfo job) {
+ final PackageManager pm = getContext().getPackageManager();
+ final ComponentName service = job.getService();
+ try {
+ ServiceInfo si = pm.getServiceInfo(service, 0);
+ if (si.applicationInfo.uid != uid) {
+ throw new IllegalArgumentException("uid " + uid +
+ " cannot schedule job in " + service.getPackageName());
+ }
+ if (!JobService.PERMISSION_BIND.equals(si.permission)) {
+ throw new IllegalArgumentException("Scheduled service " + service
+ + " does not require android.permission.BIND_JOB_SERVICE permission");
+ }
+ } catch (NameNotFoundException e) {
+ throw new IllegalArgumentException("No such service: " + service);
+ }
+ }
+
+ private boolean canPersistJobs(int pid, int uid) {
+ // If we get this far we're good to go; all we need to do now is check
+ // whether the app is allowed to persist its scheduled work.
+ final boolean canPersist;
+ synchronized (mPersistCache) {
+ Boolean cached = mPersistCache.get(uid);
+ if (cached != null) {
+ canPersist = cached.booleanValue();
+ } else {
+ // Persisting jobs is tantamount to running at boot, so we permit
+ // it when the app has declared that it uses the RECEIVE_BOOT_COMPLETED
+ // permission
+ int result = getContext().checkPermission(
+ android.Manifest.permission.RECEIVE_BOOT_COMPLETED, pid, uid);
+ canPersist = (result == PackageManager.PERMISSION_GRANTED);
+ mPersistCache.put(uid, canPersist);
+ }
+ }
+ return canPersist;
+ }
+
+ // IJobScheduler implementation
+ @Override
+ public int schedule(JobInfo job) throws RemoteException {
+ if (DEBUG) {
+ Slog.d(TAG, "Scheduling job: " + job);
+ }
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+
+ enforceValidJobRequest(uid, job);
+ final boolean canPersist = canPersistJobs(pid, uid);
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return JobSchedulerService.this.schedule(job, uid, canPersist);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public List<JobInfo> getAllPendingJobs() throws RemoteException {
+ final int uid = Binder.getCallingUid();
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return JobSchedulerService.this.getPendingJobs(uid);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void cancelAll() throws RemoteException {
+ final int uid = Binder.getCallingUid();
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ JobSchedulerService.this.cancelJobsForUid(uid);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void cancel(int jobId) throws RemoteException {
+ final int uid = Binder.getCallingUid();
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ JobSchedulerService.this.cancelJob(uid, jobId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * "dumpsys" infrastructure
+ */
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
+ long identityToken = Binder.clearCallingIdentity();
+ try {
+ JobSchedulerService.this.dumpInternal(pw);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ }
+ };
+
+ void dumpInternal(PrintWriter pw) {
+ synchronized (mJobs) {
+ pw.println("Registered jobs:");
+ if (mJobs.size() > 0) {
+ for (JobStatus job : mJobs.getJobs()) {
+ job.dump(pw, " ");
+ }
+ } else {
+ pw.println();
+ pw.println("No jobs scheduled.");
+ }
+ for (StateController controller : mControllers) {
+ pw.println();
+ controller.dumpControllerState(pw);
+ }
+ pw.println();
+ pw.println("Pending");
+ for (JobStatus jobStatus : mPendingJobs) {
+ pw.println(jobStatus.hashCode());
+ }
+ pw.println();
+ pw.println("Active jobs:");
+ for (JobServiceContext jsc : mActiveServices) {
+ if (jsc.isAvailable()) {
+ continue;
+ } else {
+ pw.println(jsc.getRunningJob().hashCode() + " for: " +
+ (SystemClock.elapsedRealtime()
+ - jsc.getExecutionStartTimeElapsed())/1000 + "s " +
+ "timeout: " + jsc.getTimeoutElapsed());
+ }
+ }
+ }
+ pw.println();
+ }
+}
diff --git a/services/core/java/com/android/server/task/TaskServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
similarity index 60%
rename from services/core/java/com/android/server/task/TaskServiceContext.java
rename to services/core/java/com/android/server/job/JobServiceContext.java
index 75e9212..534faba3 100644
--- a/services/core/java/com/android/server/task/TaskServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -14,12 +14,12 @@
* limitations under the License
*/
-package com.android.server.task;
+package com.android.server.job;
import android.app.ActivityManager;
-import android.app.task.ITaskCallback;
-import android.app.task.ITaskService;
-import android.app.task.TaskParams;
+import android.app.job.JobParameters;
+import android.app.job.IJobCallback;
+import android.app.job.IJobService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -31,40 +31,40 @@
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
import android.util.Log;
import android.util.Slog;
-import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.task.controllers.TaskStatus;
+import com.android.server.job.controllers.JobStatus;
import java.util.concurrent.atomic.AtomicBoolean;
/**
- * Handles client binding and lifecycle of a task. A task will only execute one at a time on an
+ * Handles client binding and lifecycle of a job. A job will only execute one at a time on an
* instance of this class.
*/
-public class TaskServiceContext extends ITaskCallback.Stub implements ServiceConnection {
+public class JobServiceContext extends IJobCallback.Stub implements ServiceConnection {
private static final boolean DEBUG = true;
- private static final String TAG = "TaskServiceContext";
- /** Define the maximum # of tasks allowed to run on a service at once. */
- private static final int defaultMaxActiveTasksPerService =
+ private static final String TAG = "JobServiceContext";
+ /** Define the maximum # of jobs allowed to run on a service at once. */
+ private static final int defaultMaxActiveJobsPerService =
ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
- /** Amount of time a task is allowed to execute for before being considered timed-out. */
- private static final long EXECUTING_TIMESLICE_MILLIS = 5 * 60 * 1000;
- /** Amount of time the TaskManager will wait for a response from an app for a message. */
+ /** Amount of time a job is allowed to execute for before being considered timed-out. */
+ private static final long EXECUTING_TIMESLICE_MILLIS = 60 * 1000;
+ /** Amount of time the JobScheduler will wait for a response from an app for a message. */
private static final long OP_TIMEOUT_MILLIS = 8 * 1000;
/** String prefix for all wakelock names. */
- private static final String TM_WAKELOCK_PREFIX = "*task*/";
+ private static final String JS_WAKELOCK_PREFIX = "*job*/";
private static final String[] VERB_STRINGS = {
"VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING", "VERB_PENDING"
};
- // States that a task occupies while interacting with the client.
+ // States that a job occupies while interacting with the client.
static final int VERB_BINDING = 0;
static final int VERB_STARTING = 1;
static final int VERB_EXECUTING = 2;
@@ -75,94 +75,95 @@
private static final int MSG_TIMEOUT = 0;
/** Received a callback from client. */
private static final int MSG_CALLBACK = 1;
- /** Run through list and start any ready tasks.*/
+ /** Run through list and start any ready jobs.*/
private static final int MSG_SERVICE_BOUND = 2;
- /** Cancel a task. */
+ /** Cancel a job. */
private static final int MSG_CANCEL = 3;
- /** Shutdown the Task. Used when the client crashes and we can't die gracefully.*/
+ /** Shutdown the job. Used when the client crashes and we can't die gracefully.*/
private static final int MSG_SHUTDOWN_EXECUTION = 4;
private final Handler mCallbackHandler;
- /** Make callbacks to {@link TaskManagerService} to inform on task completion status. */
- private final TaskCompletedListener mCompletedListener;
+ /** Make callbacks to {@link JobSchedulerService} to inform on job completion status. */
+ private final JobCompletedListener mCompletedListener;
/** Used for service binding, etc. */
private final Context mContext;
private PowerManager.WakeLock mWakeLock;
// Execution state.
- private TaskParams mParams;
+ private JobParameters mParams;
@VisibleForTesting
int mVerb;
private AtomicBoolean mCancelled = new AtomicBoolean();
- /** All the information maintained about the task currently being executed. */
- private TaskStatus mRunningTask;
+ /** All the information maintained about the job currently being executed. */
+ private JobStatus mRunningJob;
/** Binder to the client service. */
- ITaskService service;
+ IJobService service;
- private final Object mAvailableLock = new Object();
+ private final Object mLock = new Object();
/** Whether this context is free. */
- @GuardedBy("mAvailableLock")
+ @GuardedBy("mLock")
private boolean mAvailable;
+ /** Track start time. */
+ private long mExecutionStartTimeElapsed;
+ /** Track when job will timeout. */
+ private long mTimeoutElapsed;
- TaskServiceContext(TaskManagerService service, Looper looper) {
+ JobServiceContext(JobSchedulerService service, Looper looper) {
this(service.getContext(), service, looper);
}
@VisibleForTesting
- TaskServiceContext(Context context, TaskCompletedListener completedListener, Looper looper) {
+ JobServiceContext(Context context, JobCompletedListener completedListener, Looper looper) {
mContext = context;
- mCallbackHandler = new TaskServiceHandler(looper);
+ mCallbackHandler = new JobServiceHandler(looper);
mCompletedListener = completedListener;
+ mAvailable = true;
}
/**
- * Give a task to this context for execution. Callers must first check {@link #isAvailable()}
+ * Give a job to this context for execution. Callers must first check {@link #isAvailable()}
* to make sure this is a valid context.
- * @param ts The status of the task that we are going to run.
- * @return True if the task was accepted and is going to run.
+ * @param job The status of the job that we are going to run.
+ * @return True if the job is valid and is running. False if the job cannot be executed.
*/
- boolean executeRunnableTask(TaskStatus ts) {
- synchronized (mAvailableLock) {
+ boolean executeRunnableJob(JobStatus job) {
+ synchronized (mLock) {
if (!mAvailable) {
Slog.e(TAG, "Starting new runnable but context is unavailable > Error.");
return false;
}
- mAvailable = false;
- }
- final PowerManager pm =
- (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- TM_WAKELOCK_PREFIX + ts.getServiceComponent().getPackageName());
- mWakeLock.setWorkSource(new WorkSource(ts.getUid()));
- mWakeLock.setReferenceCounted(false);
+ mRunningJob = job;
+ mParams = new JobParameters(job.getJobId(), job.getExtras(), this);
+ mExecutionStartTimeElapsed = SystemClock.elapsedRealtime();
- mRunningTask = ts;
- mParams = new TaskParams(ts.getTaskId(), ts.getExtras(), this);
-
- mVerb = VERB_BINDING;
- final Intent intent = new Intent().setComponent(ts.getServiceComponent());
- boolean binding = mContext.bindServiceAsUser(intent, this,
- Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
- new UserHandle(ts.getUserId()));
- if (!binding) {
- if (DEBUG) {
- Slog.d(TAG, ts.getServiceComponent().getShortClassName() + " unavailable.");
+ mVerb = VERB_BINDING;
+ final Intent intent = new Intent().setComponent(job.getServiceComponent());
+ boolean binding = mContext.bindServiceAsUser(intent, this,
+ Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
+ new UserHandle(job.getUserId()));
+ if (!binding) {
+ if (DEBUG) {
+ Slog.d(TAG, job.getServiceComponent().getShortClassName() + " unavailable.");
+ }
+ mRunningJob = null;
+ mParams = null;
+ mExecutionStartTimeElapsed = 0L;
+ return false;
}
- return false;
+ mAvailable = false;
+ return true;
}
-
- return true;
}
- /** Used externally to query the running task. Will return null if there is no task running. */
- TaskStatus getRunningTask() {
- return mRunningTask;
+ /** Used externally to query the running job. Will return null if there is no job running. */
+ JobStatus getRunningJob() {
+ return mRunningJob;
}
- /** Called externally when a task that was scheduled for execution should be cancelled. */
- void cancelExecutingTask() {
+ /** Called externally when a job that was scheduled for execution should be cancelled. */
+ void cancelExecutingJob() {
mCallbackHandler.obtainMessage(MSG_CANCEL).sendToTarget();
}
@@ -170,35 +171,43 @@
* @return Whether this context is available to handle incoming work.
*/
boolean isAvailable() {
- synchronized (mAvailableLock) {
+ synchronized (mLock) {
return mAvailable;
}
}
+ long getExecutionStartTimeElapsed() {
+ return mExecutionStartTimeElapsed;
+ }
+
+ long getTimeoutElapsed() {
+ return mTimeoutElapsed;
+ }
+
@Override
- public void taskFinished(int taskId, boolean reschedule) {
+ public void jobFinished(int jobId, boolean reschedule) {
if (!verifyCallingUid()) {
return;
}
- mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, reschedule ? 1 : 0)
+ mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, reschedule ? 1 : 0)
.sendToTarget();
}
@Override
- public void acknowledgeStopMessage(int taskId, boolean reschedule) {
+ public void acknowledgeStopMessage(int jobId, boolean reschedule) {
if (!verifyCallingUid()) {
return;
}
- mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, reschedule ? 1 : 0)
+ mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, reschedule ? 1 : 0)
.sendToTarget();
}
@Override
- public void acknowledgeStartMessage(int taskId, boolean ongoing) {
+ public void acknowledgeStartMessage(int jobId, boolean ongoing) {
if (!verifyCallingUid()) {
return;
}
- mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, ongoing ? 1 : 0).sendToTarget();
+ mCallbackHandler.obtainMessage(MSG_CALLBACK, jobId, ongoing ? 1 : 0).sendToTarget();
}
/**
@@ -210,19 +219,25 @@
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- if (!name.equals(mRunningTask.getServiceComponent())) {
+ if (!name.equals(mRunningJob.getServiceComponent())) {
mCallbackHandler.obtainMessage(MSG_SHUTDOWN_EXECUTION).sendToTarget();
return;
}
- this.service = ITaskService.Stub.asInterface(service);
+ this.service = IJobService.Stub.asInterface(service);
// Remove all timeouts.
mCallbackHandler.removeMessages(MSG_TIMEOUT);
+ final PowerManager pm =
+ (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ JS_WAKELOCK_PREFIX + mRunningJob.getServiceComponent().getPackageName());
+ mWakeLock.setWorkSource(new WorkSource(mRunningJob.getUid()));
+ mWakeLock.setReferenceCounted(false);
mWakeLock.acquire();
mCallbackHandler.obtainMessage(MSG_SERVICE_BOUND).sendToTarget();
}
/**
- * If the client service crashes we reschedule this task and clean up.
+ * If the client service crashes we reschedule this job and clean up.
* @param name The concrete component name of the service whose
*/
@Override
@@ -236,7 +251,7 @@
* @return True if the binder calling is coming from the client we expect.
*/
private boolean verifyCallingUid() {
- if (mRunningTask == null || Binder.getCallingUid() != mRunningTask.getUid()) {
+ if (mRunningJob == null || Binder.getCallingUid() != mRunningJob.getUid()) {
if (DEBUG) {
Slog.d(TAG, "Stale callback received, ignoring.");
}
@@ -246,12 +261,12 @@
}
/**
- * Handles the lifecycle of the TaskService binding/callbacks, etc. The convention within this
+ * Handles the lifecycle of the JobService binding/callbacks, etc. The convention within this
* class is to append 'H' to each function name that can only be called on this handler. This
* isn't strictly necessary because all of these functions are private, but helps clarity.
*/
- private class TaskServiceHandler extends Handler {
- TaskServiceHandler(Looper looper) {
+ private class JobServiceHandler extends Handler {
+ JobServiceHandler(Looper looper) {
super(looper);
}
@@ -263,7 +278,8 @@
break;
case MSG_CALLBACK:
if (DEBUG) {
- Slog.d(TAG, "MSG_CALLBACK of : " + mRunningTask);
+ Slog.d(TAG, "MSG_CALLBACK of : " + mRunningJob + " v:" +
+ VERB_STRINGS[mVerb]);
}
removeMessages(MSG_TIMEOUT);
@@ -276,7 +292,7 @@
handleFinishedH(reschedule);
} else {
if (DEBUG) {
- Slog.d(TAG, "Unrecognised callback: " + mRunningTask);
+ Slog.d(TAG, "Unrecognised callback: " + mRunningJob);
}
}
break;
@@ -287,41 +303,42 @@
handleOpTimeoutH();
break;
case MSG_SHUTDOWN_EXECUTION:
- closeAndCleanupTaskH(true /* needsReschedule */);
+ closeAndCleanupJobH(true /* needsReschedule */);
+ break;
default:
Log.e(TAG, "Unrecognised message: " + message);
}
}
- /** Start the task on the service. */
+ /** Start the job on the service. */
private void handleServiceBoundH() {
if (mVerb != VERB_BINDING) {
- Slog.e(TAG, "Sending onStartTask for a task that isn't pending. "
+ Slog.e(TAG, "Sending onStartJob for a job that isn't pending. "
+ VERB_STRINGS[mVerb]);
- closeAndCleanupTaskH(false /* reschedule */);
+ closeAndCleanupJobH(false /* reschedule */);
return;
}
if (mCancelled.get()) {
if (DEBUG) {
- Slog.d(TAG, "Task cancelled while waiting for bind to complete. "
- + mRunningTask);
+ Slog.d(TAG, "Job cancelled while waiting for bind to complete. "
+ + mRunningJob);
}
- closeAndCleanupTaskH(true /* reschedule */);
+ closeAndCleanupJobH(true /* reschedule */);
return;
}
try {
mVerb = VERB_STARTING;
scheduleOpTimeOut();
- service.startTask(mParams);
+ service.startJob(mParams);
} catch (RemoteException e) {
Log.e(TAG, "Error sending onStart message to '" +
- mRunningTask.getServiceComponent().getShortClassName() + "' ", e);
+ mRunningJob.getServiceComponent().getShortClassName() + "' ", e);
}
}
/**
* State behaviours.
- * VERB_STARTING -> Successful start, change task to VERB_EXECUTING and post timeout.
+ * VERB_STARTING -> Successful start, change job to VERB_EXECUTING and post timeout.
* _PENDING -> Error
* _EXECUTING -> Error
* _STOPPING -> Error
@@ -331,7 +348,7 @@
case VERB_STARTING:
mVerb = VERB_EXECUTING;
if (!workOngoing) {
- // Task is finished already so fast-forward to handleFinished.
+ // Job is finished already so fast-forward to handleFinished.
handleFinishedH(false);
return;
}
@@ -343,14 +360,14 @@
scheduleOpTimeOut();
break;
default:
- Log.e(TAG, "Handling started task but task wasn't starting! Was "
+ Log.e(TAG, "Handling started job but job wasn't starting! Was "
+ VERB_STRINGS[mVerb] + ".");
return;
}
}
/**
- * VERB_EXECUTING -> Client called taskFinished(), clean up and notify done.
+ * VERB_EXECUTING -> Client called jobFinished(), clean up and notify done.
* _STOPPING -> Successful finish, clean up and notify done.
* _STARTING -> Error
* _PENDING -> Error
@@ -359,20 +376,20 @@
switch (mVerb) {
case VERB_EXECUTING:
case VERB_STOPPING:
- closeAndCleanupTaskH(reschedule);
+ closeAndCleanupJobH(reschedule);
break;
default:
- Slog.e(TAG, "Got an execution complete message for a task that wasn't being" +
+ Slog.e(TAG, "Got an execution complete message for a job that wasn't being" +
"executed. Was " + VERB_STRINGS[mVerb] + ".");
}
}
/**
- * A task can be in various states when a cancel request comes in:
+ * A job can be in various states when a cancel request comes in:
* VERB_BINDING -> Cancelled before bind completed. Mark as cancelled and wait for
* {@link #onServiceConnected(android.content.ComponentName, android.os.IBinder)}
* _STARTING -> Mark as cancelled and wait for
- * {@link TaskServiceContext#acknowledgeStartMessage(int, boolean)}
+ * {@link JobServiceContext#acknowledgeStartMessage(int, boolean)}
* _EXECUTING -> call {@link #sendStopMessageH}}.
* _ENDING -> No point in doing anything here, so we ignore.
*/
@@ -389,48 +406,48 @@
// Nada.
break;
default:
- Slog.e(TAG, "Cancelling a task without a valid verb: " + mVerb);
+ Slog.e(TAG, "Cancelling a job without a valid verb: " + mVerb);
break;
}
}
/** Process MSG_TIMEOUT here. */
private void handleOpTimeoutH() {
- if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+ if (Log.isLoggable(JobSchedulerService.TAG, Log.DEBUG)) {
Log.d(TAG, "MSG_TIMEOUT of " +
- mRunningTask.getServiceComponent().getShortClassName() + " : "
- + mParams.getTaskId());
+ mRunningJob.getServiceComponent().getShortClassName() + " : "
+ + mParams.getJobId());
}
- final int taskId = mParams.getTaskId();
+ final int jobId = mParams.getJobId();
switch (mVerb) {
case VERB_STARTING:
// Client unresponsive - wedged or failed to respond in time. We don't really
- // know what happened so let's log it and notify the TaskManager
+ // know what happened so let's log it and notify the JobScheduler
// FINISHED/NO-RETRY.
- Log.e(TAG, "No response from client for onStartTask '" +
- mRunningTask.getServiceComponent().getShortClassName() + "' tId: "
- + taskId);
- closeAndCleanupTaskH(false /* needsReschedule */);
+ Log.e(TAG, "No response from client for onStartJob '" +
+ mRunningJob.getServiceComponent().getShortClassName() + "' tId: "
+ + jobId);
+ closeAndCleanupJobH(false /* needsReschedule */);
break;
case VERB_STOPPING:
- // At least we got somewhere, so fail but ask the TaskManager to reschedule.
- Log.e(TAG, "No response from client for onStopTask, '" +
- mRunningTask.getServiceComponent().getShortClassName() + "' tId: "
- + taskId);
- closeAndCleanupTaskH(true /* needsReschedule */);
+ // At least we got somewhere, so fail but ask the JobScheduler to reschedule.
+ Log.e(TAG, "No response from client for onStopJob, '" +
+ mRunningJob.getServiceComponent().getShortClassName() + "' tId: "
+ + jobId);
+ closeAndCleanupJobH(true /* needsReschedule */);
break;
case VERB_EXECUTING:
// Not an error - client ran out of time.
- Log.i(TAG, "Client timed out while executing (no taskFinished received)." +
- " Reporting failure and asking for reschedule. " +
- mRunningTask.getServiceComponent().getShortClassName() + "' tId: "
- + taskId);
+ Log.i(TAG, "Client timed out while executing (no jobFinished received)." +
+ " sending onStop. " +
+ mRunningJob.getServiceComponent().getShortClassName() + "' tId: "
+ + jobId);
sendStopMessageH();
break;
default:
- Log.e(TAG, "Handling timeout for an unknown active task state: "
- + mRunningTask);
+ Log.e(TAG, "Handling timeout for an unknown active job state: "
+ + mRunningJob);
return;
}
}
@@ -442,41 +459,38 @@
private void sendStopMessageH() {
mCallbackHandler.removeMessages(MSG_TIMEOUT);
if (mVerb != VERB_EXECUTING) {
- Log.e(TAG, "Sending onStopTask for a task that isn't started. " + mRunningTask);
- closeAndCleanupTaskH(false /* reschedule */);
+ Log.e(TAG, "Sending onStopJob for a job that isn't started. " + mRunningJob);
+ closeAndCleanupJobH(false /* reschedule */);
return;
}
try {
mVerb = VERB_STOPPING;
scheduleOpTimeOut();
- service.stopTask(mParams);
+ service.stopJob(mParams);
} catch (RemoteException e) {
- Log.e(TAG, "Error sending onStopTask to client.", e);
- closeAndCleanupTaskH(false);
+ Log.e(TAG, "Error sending onStopJob to client.", e);
+ closeAndCleanupJobH(false /* reschedule */);
}
}
/**
- * The provided task has finished, either by calling
- * {@link android.app.task.TaskService#taskFinished(android.app.task.TaskParams, boolean)}
+ * The provided job has finished, either by calling
+ * {@link android.app.job.JobService#jobFinished(android.app.job.JobParameters, boolean)}
* or from acknowledging the stop message we sent. Either way, we're done tracking it and
* we want to clean up internally.
*/
- private void closeAndCleanupTaskH(boolean reschedule) {
+ private void closeAndCleanupJobH(boolean reschedule) {
removeMessages(MSG_TIMEOUT);
- mWakeLock.release();
- mContext.unbindService(TaskServiceContext.this);
- mWakeLock = null;
-
- mRunningTask = null;
- mParams = null;
- mVerb = -1;
- mCancelled.set(false);
-
- service = null;
-
- mCompletedListener.onTaskCompleted(mRunningTask, reschedule);
- synchronized (mAvailableLock) {
+ mCompletedListener.onJobCompleted(mRunningJob, reschedule);
+ synchronized (mLock) {
+ mWakeLock.release();
+ mContext.unbindService(JobServiceContext.this);
+ mWakeLock = null;
+ mRunningJob = null;
+ mParams = null;
+ mVerb = -1;
+ mCancelled.set(false);
+ service = null;
mAvailable = true;
}
}
@@ -493,11 +507,12 @@
EXECUTING_TIMESLICE_MILLIS : OP_TIMEOUT_MILLIS;
if (DEBUG) {
Slog.d(TAG, "Scheduling time out for '" +
- mRunningTask.getServiceComponent().getShortClassName() + "' tId: " +
- mParams.getTaskId() + ", in " + (timeoutMillis / 1000) + " s");
+ mRunningJob.getServiceComponent().getShortClassName() + "' tId: " +
+ mParams.getJobId() + ", in " + (timeoutMillis / 1000) + " s");
}
Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT);
mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
+ mTimeoutElapsed = SystemClock.elapsedRealtime() + timeoutMillis;
}
}
}
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
new file mode 100644
index 0000000..4ac26c1
--- /dev/null
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -0,0 +1,669 @@
+/*
+ * 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.server.job;
+
+import android.content.ComponentName;
+import android.app.job.JobInfo;
+import android.content.Context;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.PersistableBundle;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.AtomicFile;
+import android.util.ArraySet;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.server.IoThread;
+import com.android.server.job.controllers.JobStatus;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+/**
+ * Maintain a list of classes, and accessor methods/logic for these jobs.
+ * This class offers the following functionality:
+ * - When a job is added, it will determine if the job requirements have changed (update) and
+ * whether the controllers need to be updated.
+ * - Persists JobInfos, figures out when to to rewrite the JobInfo to disk.
+ * - Handles rescheduling of jobs.
+ * - When a periodic job is executed and must be re-added.
+ * - When a job fails and the client requests that it be retried with backoff.
+ * - This class <strong>is not</strong> thread-safe.
+ *
+ * Note on locking:
+ * All callers to this class must <strong>lock on the class object they are calling</strong>.
+ * This is important b/c {@link com.android.server.job.JobStore.WriteJobsMapToDiskRunnable}
+ * and {@link com.android.server.job.JobStore.ReadJobMapFromDiskRunnable} lock on that
+ * object.
+ */
+public class JobStore {
+ private static final String TAG = "JobStore";
+ private static final boolean DEBUG = JobSchedulerService.DEBUG;
+
+ /** Threshold to adjust how often we want to write to the db. */
+ private static final int MAX_OPS_BEFORE_WRITE = 1;
+ final ArraySet<JobStatus> mJobSet;
+ final Context mContext;
+
+ private int mDirtyOperations;
+
+ private static final Object sSingletonLock = new Object();
+ private final AtomicFile mJobsFile;
+ /** Handler backed by IoThread for writing to disk. */
+ private final Handler mIoHandler = IoThread.getHandler();
+ private static JobStore sSingleton;
+
+ /** Used by the {@link JobSchedulerService} to instantiate the JobStore. */
+ static JobStore initAndGet(JobSchedulerService jobManagerService) {
+ synchronized (sSingletonLock) {
+ if (sSingleton == null) {
+ sSingleton = new JobStore(jobManagerService.getContext(),
+ Environment.getDataDirectory(), jobManagerService);
+ }
+ return sSingleton;
+ }
+ }
+
+ @VisibleForTesting
+ public static JobStore initAndGetForTesting(Context context, File dataDir,
+ JobMapReadFinishedListener callback) {
+ return new JobStore(context, dataDir, callback);
+ }
+
+ private JobStore(Context context, File dataDir, JobMapReadFinishedListener callback) {
+ mContext = context;
+ mDirtyOperations = 0;
+
+ File systemDir = new File(dataDir, "system");
+ File jobDir = new File(systemDir, "job");
+ jobDir.mkdirs();
+ mJobsFile = new AtomicFile(new File(jobDir, "jobs.xml"));
+
+ mJobSet = new ArraySet<JobStatus>();
+
+ readJobMapFromDiskAsync(callback);
+ }
+
+ /**
+ * Add a job to the master list, persisting it if necessary. If the JobStatus already exists,
+ * it will be replaced.
+ * @param jobStatus Job to add.
+ * @return Whether or not an equivalent JobStatus was replaced by this operation.
+ */
+ public boolean add(JobStatus jobStatus) {
+ boolean replaced = mJobSet.remove(jobStatus);
+ mJobSet.add(jobStatus);
+ if (jobStatus.isPersisted()) {
+ maybeWriteStatusToDiskAsync();
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "Added job status to store: " + jobStatus);
+ }
+ return replaced;
+ }
+
+ /**
+ * Whether this jobStatus object already exists in the JobStore.
+ */
+ public boolean containsJobIdForUid(int jobId, int uId) {
+ for (JobStatus ts : mJobSet) {
+ if (ts.getUid() == uId && ts.getJobId() == jobId) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public int size() {
+ return mJobSet.size();
+ }
+
+ /**
+ * Remove the provided job. Will also delete the job if it was persisted.
+ * @return Whether or not the job existed to be removed.
+ */
+ public boolean remove(JobStatus jobStatus) {
+ boolean removed = mJobSet.remove(jobStatus);
+ if (!removed) {
+ if (DEBUG) {
+ Slog.d(TAG, "Couldn't remove job: didn't exist: " + jobStatus);
+ }
+ return false;
+ }
+ maybeWriteStatusToDiskAsync();
+ return removed;
+ }
+
+ @VisibleForTesting
+ public void clear() {
+ mJobSet.clear();
+ maybeWriteStatusToDiskAsync();
+ }
+
+ public List<JobStatus> getJobsByUser(int userHandle) {
+ List<JobStatus> matchingJobs = new ArrayList<JobStatus>();
+ Iterator<JobStatus> it = mJobSet.iterator();
+ while (it.hasNext()) {
+ JobStatus ts = it.next();
+ if (UserHandle.getUserId(ts.getUid()) == userHandle) {
+ matchingJobs.add(ts);
+ }
+ }
+ return matchingJobs;
+ }
+
+ /**
+ * @param uid Uid of the requesting app.
+ * @return All JobStatus objects for a given uid from the master list.
+ */
+ public List<JobStatus> getJobsByUid(int uid) {
+ List<JobStatus> matchingJobs = new ArrayList<JobStatus>();
+ Iterator<JobStatus> it = mJobSet.iterator();
+ while (it.hasNext()) {
+ JobStatus ts = it.next();
+ if (ts.getUid() == uid) {
+ matchingJobs.add(ts);
+ }
+ }
+ return matchingJobs;
+ }
+
+ /**
+ * @param uid Uid of the requesting app.
+ * @param jobId Job id, specified at schedule-time.
+ * @return the JobStatus that matches the provided uId and jobId, or null if none found.
+ */
+ public JobStatus getJobByUidAndJobId(int uid, int jobId) {
+ Iterator<JobStatus> it = mJobSet.iterator();
+ while (it.hasNext()) {
+ JobStatus ts = it.next();
+ if (ts.getUid() == uid && ts.getJobId() == jobId) {
+ return ts;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @return The live array of JobStatus objects.
+ */
+ public ArraySet<JobStatus> getJobs() {
+ return mJobSet;
+ }
+
+ /** Version of the db schema. */
+ private static final int JOBS_FILE_VERSION = 0;
+ /** Tag corresponds to constraints this job needs. */
+ private static final String XML_TAG_PARAMS_CONSTRAINTS = "constraints";
+ /** Tag corresponds to execution parameters. */
+ private static final String XML_TAG_PERIODIC = "periodic";
+ private static final String XML_TAG_ONEOFF = "one-off";
+ private static final String XML_TAG_EXTRAS = "extras";
+
+ /**
+ * Every time the state changes we write all the jobs in one swath, instead of trying to
+ * track incremental changes.
+ * @return Whether the operation was successful. This will only fail for e.g. if the system is
+ * low on storage. If this happens, we continue as normal
+ */
+ private void maybeWriteStatusToDiskAsync() {
+ mDirtyOperations++;
+ if (mDirtyOperations >= MAX_OPS_BEFORE_WRITE) {
+ if (DEBUG) {
+ Slog.v(TAG, "Writing jobs to disk.");
+ }
+ mIoHandler.post(new WriteJobsMapToDiskRunnable());
+ }
+ }
+
+ private void readJobMapFromDiskAsync(JobMapReadFinishedListener callback) {
+ mIoHandler.post(new ReadJobMapFromDiskRunnable(callback));
+ }
+
+ public void readJobMapFromDisk(JobMapReadFinishedListener callback) {
+ new ReadJobMapFromDiskRunnable(callback).run();
+ }
+
+ /**
+ * Runnable that writes {@link #mJobSet} out to xml.
+ * NOTE: This Runnable locks on JobStore.this
+ */
+ private class WriteJobsMapToDiskRunnable implements Runnable {
+ @Override
+ public void run() {
+ final long startElapsed = SystemClock.elapsedRealtime();
+ List<JobStatus> mStoreCopy = new ArrayList<JobStatus>();
+ synchronized (JobStore.this) {
+ // Copy over the jobs so we can release the lock before writing.
+ for (JobStatus jobStatus : mJobSet) {
+ JobStatus copy = new JobStatus(jobStatus.getJob(), jobStatus.getUid(),
+ jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
+ mStoreCopy.add(copy);
+ }
+ }
+ writeJobsMapImpl(mStoreCopy);
+ if (JobSchedulerService.DEBUG) {
+ Slog.v(TAG, "Finished writing, took " + (SystemClock.elapsedRealtime()
+ - startElapsed) + "ms");
+ }
+ }
+
+ private void writeJobsMapImpl(List<JobStatus> jobList) {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(baos, "utf-8");
+ out.startDocument(null, true);
+ out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ out.startTag(null, "job-info");
+ out.attribute(null, "version", Integer.toString(JOBS_FILE_VERSION));
+ for (JobStatus jobStatus : jobList) {
+ if (DEBUG) {
+ Slog.d(TAG, "Saving job " + jobStatus.getJobId());
+ }
+ out.startTag(null, "job");
+ addIdentifierAttributesToJobTag(out, jobStatus);
+ writeConstraintsToXml(out, jobStatus);
+ writeExecutionCriteriaToXml(out, jobStatus);
+ writeBundleToXml(jobStatus.getExtras(), out);
+ out.endTag(null, "job");
+ }
+ out.endTag(null, "job-info");
+ out.endDocument();
+
+ // Write out to disk in one fell sweep.
+ FileOutputStream fos = mJobsFile.startWrite();
+ fos.write(baos.toByteArray());
+ mJobsFile.finishWrite(fos);
+ mDirtyOperations = 0;
+ } catch (IOException e) {
+ if (DEBUG) {
+ Slog.v(TAG, "Error writing out job data.", e);
+ }
+ } catch (XmlPullParserException e) {
+ if (DEBUG) {
+ Slog.d(TAG, "Error persisting bundle.", e);
+ }
+ }
+ }
+
+ /** Write out a tag with data comprising the required fields of this job and its client. */
+ private void addIdentifierAttributesToJobTag(XmlSerializer out, JobStatus jobStatus)
+ throws IOException {
+ out.attribute(null, "jobid", Integer.toString(jobStatus.getJobId()));
+ out.attribute(null, "package", jobStatus.getServiceComponent().getPackageName());
+ out.attribute(null, "class", jobStatus.getServiceComponent().getClassName());
+ out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
+ }
+
+ private void writeBundleToXml(PersistableBundle extras, XmlSerializer out)
+ throws IOException, XmlPullParserException {
+ out.startTag(null, XML_TAG_EXTRAS);
+ extras.saveToXml(out);
+ out.endTag(null, XML_TAG_EXTRAS);
+ }
+ /**
+ * Write out a tag with data identifying this job's constraints. If the constraint isn't here
+ * it doesn't apply.
+ */
+ private void writeConstraintsToXml(XmlSerializer out, JobStatus jobStatus) throws IOException {
+ out.startTag(null, XML_TAG_PARAMS_CONSTRAINTS);
+ if (jobStatus.hasUnmeteredConstraint()) {
+ out.attribute(null, "unmetered", Boolean.toString(true));
+ }
+ if (jobStatus.hasConnectivityConstraint()) {
+ out.attribute(null, "connectivity", Boolean.toString(true));
+ }
+ if (jobStatus.hasIdleConstraint()) {
+ out.attribute(null, "idle", Boolean.toString(true));
+ }
+ if (jobStatus.hasChargingConstraint()) {
+ out.attribute(null, "charging", Boolean.toString(true));
+ }
+ out.endTag(null, XML_TAG_PARAMS_CONSTRAINTS);
+ }
+
+ private void writeExecutionCriteriaToXml(XmlSerializer out, JobStatus jobStatus)
+ throws IOException {
+ final JobInfo job = jobStatus.getJob();
+ if (jobStatus.getJob().isPeriodic()) {
+ out.startTag(null, XML_TAG_PERIODIC);
+ out.attribute(null, "period", Long.toString(job.getIntervalMillis()));
+ } else {
+ out.startTag(null, XML_TAG_ONEOFF);
+ }
+
+ if (jobStatus.hasDeadlineConstraint()) {
+ // Wall clock deadline.
+ final long deadlineWallclock = System.currentTimeMillis() +
+ (jobStatus.getLatestRunTimeElapsed() - SystemClock.elapsedRealtime());
+ out.attribute(null, "deadline", Long.toString(deadlineWallclock));
+ }
+ if (jobStatus.hasTimingDelayConstraint()) {
+ final long delayWallclock = System.currentTimeMillis() +
+ (jobStatus.getEarliestRunTime() - SystemClock.elapsedRealtime());
+ out.attribute(null, "delay", Long.toString(delayWallclock));
+ }
+
+ // Only write out back-off policy if it differs from the default.
+ // This also helps the case where the job is idle -> these aren't allowed to specify
+ // back-off.
+ if (jobStatus.getJob().getInitialBackoffMillis() != JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS
+ || jobStatus.getJob().getBackoffPolicy() != JobInfo.DEFAULT_BACKOFF_POLICY) {
+ out.attribute(null, "backoff-policy", Integer.toString(job.getBackoffPolicy()));
+ out.attribute(null, "initial-backoff", Long.toString(job.getInitialBackoffMillis()));
+ }
+ if (job.isPeriodic()) {
+ out.endTag(null, XML_TAG_PERIODIC);
+ } else {
+ out.endTag(null, XML_TAG_ONEOFF);
+ }
+ }
+ }
+
+ /**
+ * Runnable that reads list of persisted job from xml.
+ * NOTE: This Runnable locks on JobStore.this
+ */
+ private class ReadJobMapFromDiskRunnable implements Runnable {
+ private JobMapReadFinishedListener mCallback;
+ public ReadJobMapFromDiskRunnable(JobMapReadFinishedListener callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void run() {
+ try {
+ List<JobStatus> jobs;
+ FileInputStream fis = mJobsFile.openRead();
+ synchronized (JobStore.this) {
+ jobs = readJobMapImpl(fis);
+ }
+ fis.close();
+ if (jobs != null) {
+ mCallback.onJobMapReadFinished(jobs);
+ }
+ } catch (FileNotFoundException e) {
+ if (JobSchedulerService.DEBUG) {
+ Slog.d(TAG, "Could not find jobs file, probably there was nothing to load.");
+ }
+ } catch (XmlPullParserException e) {
+ if (JobSchedulerService.DEBUG) {
+ Slog.d(TAG, "Error parsing xml.", e);
+ }
+ } catch (IOException e) {
+ if (JobSchedulerService.DEBUG) {
+ Slog.d(TAG, "Error parsing xml.", e);
+ }
+ }
+ }
+
+ private List<JobStatus> readJobMapImpl(FileInputStream fis) throws XmlPullParserException, IOException {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(fis, null);
+
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.START_TAG &&
+ eventType != XmlPullParser.END_DOCUMENT) {
+ eventType = parser.next();
+ Slog.d(TAG, parser.getName());
+ }
+ if (eventType == XmlPullParser.END_DOCUMENT) {
+ if (DEBUG) {
+ Slog.d(TAG, "No persisted jobs.");
+ }
+ return null;
+ }
+
+ String tagName = parser.getName();
+ if ("job-info".equals(tagName)) {
+ final List<JobStatus> jobs = new ArrayList<JobStatus>();
+ // Read in version info.
+ try {
+ int version = Integer.valueOf(parser.getAttributeValue(null, "version"));
+ if (version != JOBS_FILE_VERSION) {
+ Slog.d(TAG, "Invalid version number, aborting jobs file read.");
+ return null;
+ }
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, "Invalid version number, aborting jobs file read.");
+ return null;
+ }
+ eventType = parser.next();
+ do {
+ // Read each <job/>
+ if (eventType == XmlPullParser.START_TAG) {
+ tagName = parser.getName();
+ // Start reading job.
+ if ("job".equals(tagName)) {
+ JobStatus persistedJob = restoreJobFromXml(parser);
+ if (persistedJob != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "Read out " + persistedJob);
+ }
+ jobs.add(persistedJob);
+ } else {
+ Slog.d(TAG, "Error reading job from file.");
+ }
+ }
+ }
+ eventType = parser.next();
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+ return jobs;
+ }
+ return null;
+ }
+
+ /**
+ * @param parser Xml parser at the beginning of a "<job/>" tag. The next "parser.next()" call
+ * will take the parser into the body of the job tag.
+ * @return Newly instantiated job holding all the information we just read out of the xml tag.
+ */
+ private JobStatus restoreJobFromXml(XmlPullParser parser) throws XmlPullParserException,
+ IOException {
+ JobInfo.Builder jobBuilder;
+ int uid;
+
+ // Read out job identifier attributes.
+ try {
+ jobBuilder = buildBuilderFromXml(parser);
+ uid = Integer.valueOf(parser.getAttributeValue(null, "uid"));
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, "Error parsing job's required fields, skipping");
+ return null;
+ }
+
+ int eventType;
+ // Read out constraints tag.
+ do {
+ eventType = parser.next();
+ } while (eventType == XmlPullParser.TEXT); // Push through to next START_TAG.
+
+ if (!(eventType == XmlPullParser.START_TAG &&
+ XML_TAG_PARAMS_CONSTRAINTS.equals(parser.getName()))) {
+ // Expecting a <constraints> start tag.
+ return null;
+ }
+ try {
+ buildConstraintsFromXml(jobBuilder, parser);
+ } catch (NumberFormatException e) {
+ Slog.d(TAG, "Error reading constraints, skipping.");
+ return null;
+ }
+ parser.next(); // Consume </constraints>
+
+ // Read out execution parameters tag.
+ do {
+ eventType = parser.next();
+ } while (eventType == XmlPullParser.TEXT);
+ if (eventType != XmlPullParser.START_TAG) {
+ return null;
+ }
+
+ Pair<Long, Long> runtimes;
+ try {
+ runtimes = buildExecutionTimesFromXml(parser);
+ } catch (NumberFormatException e) {
+ if (DEBUG) {
+ Slog.d(TAG, "Error parsing execution time parameters, skipping.");
+ }
+ return null;
+ }
+
+ if (XML_TAG_PERIODIC.equals(parser.getName())) {
+ try {
+ String val = parser.getAttributeValue(null, "period");
+ jobBuilder.setPeriodic(Long.valueOf(val));
+ } catch (NumberFormatException e) {
+ Slog.d(TAG, "Error reading periodic execution criteria, skipping.");
+ return null;
+ }
+ } else if (XML_TAG_ONEOFF.equals(parser.getName())) {
+ try {
+ if (runtimes.first != JobStatus.NO_EARLIEST_RUNTIME) {
+ jobBuilder.setMinimumLatency(runtimes.first - SystemClock.elapsedRealtime());
+ }
+ if (runtimes.second != JobStatus.NO_LATEST_RUNTIME) {
+ jobBuilder.setOverrideDeadline(
+ runtimes.second - SystemClock.elapsedRealtime());
+ }
+ } catch (NumberFormatException e) {
+ Slog.d(TAG, "Error reading job execution criteria, skipping.");
+ return null;
+ }
+ } else {
+ if (DEBUG) {
+ Slog.d(TAG, "Invalid parameter tag, skipping - " + parser.getName());
+ }
+ // Expecting a parameters start tag.
+ return null;
+ }
+ maybeBuildBackoffPolicyFromXml(jobBuilder, parser);
+
+ parser.nextTag(); // Consume parameters end tag.
+
+ // Read out extras Bundle.
+ do {
+ eventType = parser.next();
+ } while (eventType == XmlPullParser.TEXT);
+ if (!(eventType == XmlPullParser.START_TAG && XML_TAG_EXTRAS.equals(parser.getName()))) {
+ if (DEBUG) {
+ Slog.d(TAG, "Error reading extras, skipping.");
+ }
+ return null;
+ }
+
+ PersistableBundle extras = PersistableBundle.restoreFromXml(parser);
+ jobBuilder.setExtras(extras);
+ parser.nextTag(); // Consume </extras>
+
+ return new JobStatus(jobBuilder.build(), uid, runtimes.first, runtimes.second);
+ }
+
+ private JobInfo.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberFormatException {
+ // Pull out required fields from <job> attributes.
+ int jobId = Integer.valueOf(parser.getAttributeValue(null, "jobid"));
+ String packageName = parser.getAttributeValue(null, "package");
+ String className = parser.getAttributeValue(null, "class");
+ ComponentName cname = new ComponentName(packageName, className);
+
+ return new JobInfo.Builder(jobId, cname);
+ }
+
+ private void buildConstraintsFromXml(JobInfo.Builder jobBuilder, XmlPullParser parser) {
+ String val = parser.getAttributeValue(null, "unmetered");
+ if (val != null) {
+ jobBuilder.setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED);
+ }
+ val = parser.getAttributeValue(null, "connectivity");
+ if (val != null) {
+ jobBuilder.setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY);
+ }
+ val = parser.getAttributeValue(null, "idle");
+ if (val != null) {
+ jobBuilder.setRequiresDeviceIdle(true);
+ }
+ val = parser.getAttributeValue(null, "charging");
+ if (val != null) {
+ jobBuilder.setRequiresCharging(true);
+ }
+ }
+
+ /**
+ * Builds the back-off policy out of the params tag. These attributes may not exist, depending
+ * on whether the back-off was set when the job was first scheduled.
+ */
+ private void maybeBuildBackoffPolicyFromXml(JobInfo.Builder jobBuilder, XmlPullParser parser) {
+ String val = parser.getAttributeValue(null, "initial-backoff");
+ if (val != null) {
+ long initialBackoff = Long.valueOf(val);
+ val = parser.getAttributeValue(null, "backoff-policy");
+ int backoffPolicy = Integer.valueOf(val); // Will throw NFE which we catch higher up.
+ jobBuilder.setBackoffCriteria(initialBackoff, backoffPolicy);
+ }
+ }
+
+ /**
+ * Convenience function to read out and convert deadline and delay from xml into elapsed real
+ * time.
+ * @return A {@link android.util.Pair}, where the first value is the earliest elapsed runtime
+ * and the second is the latest elapsed runtime.
+ */
+ private Pair<Long, Long> buildExecutionTimesFromXml(XmlPullParser parser)
+ throws NumberFormatException {
+ // Pull out execution time data.
+ final long nowWallclock = System.currentTimeMillis();
+ final long nowElapsed = SystemClock.elapsedRealtime();
+
+ long earliestRunTimeElapsed = JobStatus.NO_EARLIEST_RUNTIME;
+ long latestRunTimeElapsed = JobStatus.NO_LATEST_RUNTIME;
+ String val = parser.getAttributeValue(null, "deadline");
+ if (val != null) {
+ long latestRuntimeWallclock = Long.valueOf(val);
+ long maxDelayElapsed =
+ Math.max(latestRuntimeWallclock - nowWallclock, 0);
+ latestRunTimeElapsed = nowElapsed + maxDelayElapsed;
+ }
+ val = parser.getAttributeValue(null, "delay");
+ if (val != null) {
+ long earliestRuntimeWallclock = Long.valueOf(val);
+ long minDelayElapsed =
+ Math.max(earliestRuntimeWallclock - nowWallclock, 0);
+ earliestRunTimeElapsed = nowElapsed + minDelayElapsed;
+
+ }
+ return Pair.create(earliestRunTimeElapsed, latestRunTimeElapsed);
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/job/StateChangedListener.java b/services/core/java/com/android/server/job/StateChangedListener.java
new file mode 100644
index 0000000..90c203a
--- /dev/null
+++ b/services/core/java/com/android/server/job/StateChangedListener.java
@@ -0,0 +1,39 @@
+/*
+ * 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.server.job;
+
+import com.android.server.job.controllers.JobStatus;
+
+/**
+ * Interface through which a {@link com.android.server.job.controllers.StateController} informs
+ * the {@link com.android.server.job.JobSchedulerService} that there are some tasks potentially
+ * ready to be run.
+ */
+public interface StateChangedListener {
+ /**
+ * Called by the controller to notify the JobManager that it should check on the state of a
+ * task.
+ */
+ public void onControllerStateChanged();
+
+ /**
+ * Called by the controller to notify the JobManager that regardless of the state of the task,
+ * it must be run immediately.
+ * @param jobStatus The state of the task which is to be run immediately.
+ */
+ public void onRunJobNow(JobStatus jobStatus);
+}
diff --git a/services/core/java/com/android/server/task/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
similarity index 79%
rename from services/core/java/com/android/server/task/controllers/BatteryController.java
rename to services/core/java/com/android/server/job/controllers/BatteryController.java
index 4727e9a..4aef2d31 100644
--- a/services/core/java/com/android/server/task/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.server.task.controllers;
+package com.android.server.job.controllers;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -32,10 +32,12 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.BatteryService;
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
+import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
/**
@@ -44,7 +46,7 @@
* ACTION_BATTERY_OK.
*/
public class BatteryController extends StateController {
- private static final String TAG = "BatteryController";
+ private static final String TAG = "JobScheduler.Batt";
private static final Object sCreationLock = new Object();
private static volatile BatteryController sController;
@@ -53,10 +55,10 @@
/** Wait this long after phone is plugged in before doing any work. */
private static final long STABLE_CHARGING_THRESHOLD_MILLIS = 2 * 60 * 1000; // 2 minutes.
- private List<TaskStatus> mTrackedTasks = new ArrayList<TaskStatus>();
+ private List<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
private ChargingTracker mChargeTracker;
- public static BatteryController get(TaskManagerService taskManagerService) {
+ public static BatteryController get(JobSchedulerService taskManagerService) {
synchronized (sCreationLock) {
if (sController == null) {
sController = new BatteryController(taskManagerService,
@@ -84,18 +86,21 @@
}
@Override
- public void maybeStartTrackingTask(TaskStatus taskStatus) {
+ public void maybeStartTrackingJob(JobStatus taskStatus) {
if (taskStatus.hasChargingConstraint()) {
+ final boolean isOnStablePower = mChargeTracker.isOnStablePower();
synchronized (mTrackedTasks) {
mTrackedTasks.add(taskStatus);
- taskStatus.chargingConstraintSatisfied.set(mChargeTracker.isOnStablePower());
+ taskStatus.chargingConstraintSatisfied.set(isOnStablePower);
+ }
+ if (isOnStablePower) {
+ mStateChangedListener.onControllerStateChanged();
}
}
-
}
@Override
- public void maybeStopTrackingTask(TaskStatus taskStatus) {
+ public void maybeStopTrackingJob(JobStatus taskStatus) {
if (taskStatus.hasChargingConstraint()) {
synchronized (mTrackedTasks) {
mTrackedTasks.remove(taskStatus);
@@ -105,9 +110,12 @@
private void maybeReportNewChargingState() {
final boolean stablePower = mChargeTracker.isOnStablePower();
+ if (DEBUG) {
+ Slog.d(TAG, "maybeReportNewChargingState: " + stablePower);
+ }
boolean reportChange = false;
synchronized (mTrackedTasks) {
- for (TaskStatus ts : mTrackedTasks) {
+ for (JobStatus ts : mTrackedTasks) {
boolean previous = ts.chargingConstraintSatisfied.getAndSet(stablePower);
if (previous != stablePower) {
reportChange = true;
@@ -132,8 +140,7 @@
public ChargingTracker() {
mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- Intent intent = new Intent(ACTION_CHARGING_STABLE)
- .setComponent(new ComponentName(mContext, this.getClass()));
+ Intent intent = new Intent(ACTION_CHARGING_STABLE);
mStableChargingTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
}
@@ -146,6 +153,8 @@
// Charging/not charging.
filter.addAction(Intent.ACTION_POWER_CONNECTED);
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
+ // Charging stable.
+ filter.addAction(ACTION_CHARGING_STABLE);
mContext.registerReceiver(this, filter);
// Initialise tracker state.
@@ -188,6 +197,10 @@
mBatteryHealthy = true;
maybeReportNewChargingState();
} else if (Intent.ACTION_POWER_CONNECTED.equals(action)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Received charging intent, setting alarm for "
+ + STABLE_CHARGING_THRESHOLD_MILLIS);
+ }
// Set up an alarm for ACTION_CHARGING_STABLE - we don't want to kick off tasks
// here if the user unplugs the phone immediately.
mAlarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
@@ -195,6 +208,9 @@
mStableChargingTriggerIntent);
mCharging = true;
} else if (Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Disconnected from power, cancelling any set alarms.");
+ }
// If an alarm is set, breathe a sigh of relief and cancel it - crisis averted.
mAlarm.cancel(mStableChargingTriggerIntent);
mCharging = false;
@@ -202,7 +218,8 @@
}else if (ACTION_CHARGING_STABLE.equals(action)) {
// Here's where we actually do the notify for a task being ready.
if (DEBUG) {
- Slog.d(TAG, "Battery connected fired @ " + SystemClock.elapsedRealtime());
+ Slog.d(TAG, "Battery connected fired @ " + SystemClock.elapsedRealtime()
+ + " charging: " + mCharging);
}
if (mCharging) { // Should never receive this intent if mCharging is false.
maybeReportNewChargingState();
@@ -210,4 +227,20 @@
}
}
}
+
+ @Override
+ public void dumpControllerState(PrintWriter pw) {
+ pw.println("Batt.");
+ pw.println("Stable power: " + mChargeTracker.isOnStablePower());
+ synchronized (mTrackedTasks) {
+ Iterator<JobStatus> it = mTrackedTasks.iterator();
+ if (it.hasNext()) {
+ pw.print(String.valueOf(it.next().hashCode()));
+ }
+ while (it.hasNext()) {
+ pw.print("," + String.valueOf(it.next().hashCode()));
+ }
+ pw.println();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
new file mode 100644
index 0000000..daba0d9
--- /dev/null
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -0,0 +1,200 @@
+/*
+ * 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.server.job.controllers;
+
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.server.ConnectivityService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
+
+import java.io.PrintWriter;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Handles changes in connectivity.
+ * We are only interested in metered vs. unmetered networks, and we're interested in them on a
+ * per-user basis.
+ */
+public class ConnectivityController extends StateController implements
+ ConnectivityManager.OnNetworkActiveListener {
+ private static final String TAG = "JobScheduler.Conn";
+
+ private final List<JobStatus> mTrackedJobs = new LinkedList<JobStatus>();
+ private final BroadcastReceiver mConnectivityChangedReceiver =
+ new ConnectivityChangedReceiver();
+ /** Singleton. */
+ private static ConnectivityController mSingleton;
+ private static Object sCreationLock = new Object();
+ /** Track whether the latest active network is metered. */
+ private boolean mNetworkUnmetered;
+ /** Track whether the latest active network is connected. */
+ private boolean mNetworkConnected;
+
+ public static ConnectivityController get(JobSchedulerService jms) {
+ synchronized (sCreationLock) {
+ if (mSingleton == null) {
+ mSingleton = new ConnectivityController(jms, jms.getContext());
+ }
+ return mSingleton;
+ }
+ }
+
+ private ConnectivityController(StateChangedListener stateChangedListener, Context context) {
+ super(stateChangedListener, context);
+ // Register connectivity changed BR.
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ mContext.registerReceiverAsUser(
+ mConnectivityChangedReceiver, UserHandle.ALL, intentFilter, null, null);
+ ConnectivityService cs =
+ (ConnectivityService)ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+ if (cs != null) {
+ if (cs.getActiveNetworkInfo() != null) {
+ mNetworkConnected = cs.getActiveNetworkInfo().isConnected();
+ }
+ mNetworkUnmetered = mNetworkConnected && !cs.isActiveNetworkMetered();
+ }
+ }
+
+ @Override
+ public void maybeStartTrackingJob(JobStatus jobStatus) {
+ if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
+ synchronized (mTrackedJobs) {
+ jobStatus.connectivityConstraintSatisfied.set(mNetworkConnected);
+ jobStatus.unmeteredConstraintSatisfied.set(mNetworkUnmetered);
+ mTrackedJobs.add(jobStatus);
+ }
+ }
+ }
+
+ @Override
+ public void maybeStopTrackingJob(JobStatus jobStatus) {
+ if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
+ synchronized (mTrackedJobs) {
+ mTrackedJobs.remove(jobStatus);
+ }
+ }
+ }
+
+ /**
+ * @param userId Id of the user for whom we are updating the connectivity state.
+ */
+ private void updateTrackedJobs(int userId) {
+ synchronized (mTrackedJobs) {
+ boolean changed = false;
+ for (JobStatus js : mTrackedJobs) {
+ if (js.getUserId() != userId) {
+ continue;
+ }
+ boolean prevIsConnected =
+ js.connectivityConstraintSatisfied.getAndSet(mNetworkConnected);
+ boolean prevIsMetered = js.unmeteredConstraintSatisfied.getAndSet(mNetworkUnmetered);
+ if (prevIsConnected != mNetworkConnected || prevIsMetered != mNetworkUnmetered) {
+ changed = true;
+ }
+ }
+ if (changed) {
+ mStateChangedListener.onControllerStateChanged();
+ }
+ }
+ }
+
+ /**
+ * We know the network has just come up. We want to run any jobs that are ready.
+ */
+ public synchronized void onNetworkActive() {
+ synchronized (mTrackedJobs) {
+ for (JobStatus js : mTrackedJobs) {
+ if (js.isReady()) {
+ if (DEBUG) {
+ Slog.d(TAG, "Running " + js + " due to network activity.");
+ }
+ mStateChangedListener.onRunJobNow(js);
+ }
+ }
+ }
+ }
+
+ class ConnectivityChangedReceiver extends BroadcastReceiver {
+ /**
+ * We'll receive connectivity changes for each user here, which we process independently.
+ * We are only interested in the active network here. We're only interested in the active
+ * network, b/c the end result of this will be for apps to try to hit the network.
+ * @param context The Context in which the receiver is running.
+ * @param intent The Intent being received.
+ */
+ // TODO: Test whether this will be called twice for each user.
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) {
+ Slog.d(TAG, "Received connectivity event: " + intent.getAction() + " u"
+ + context.getUserId());
+ }
+ final String action = intent.getAction();
+ if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+ final int networkType =
+ intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
+ ConnectivityManager.TYPE_NONE);
+ // Connectivity manager for THIS context - important!
+ final ConnectivityManager connManager = (ConnectivityManager)
+ context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
+ final int userid = context.getUserId();
+ // This broadcast gets sent a lot, only update if the active network has changed.
+ if (activeNetwork == null) {
+ mNetworkUnmetered = false;
+ mNetworkConnected = false;
+ updateTrackedJobs(userid);
+ } else if (activeNetwork.getType() == networkType) {
+ mNetworkUnmetered = false;
+ mNetworkConnected = !intent.getBooleanExtra(
+ ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
+ if (mNetworkConnected) { // No point making the call if we know there's no conn.
+ mNetworkUnmetered = !connManager.isActiveNetworkMetered();
+ }
+ updateTrackedJobs(userid);
+ }
+ } else {
+ if (DEBUG) {
+ Slog.d(TAG, "Unrecognised action in intent: " + action);
+ }
+ }
+ }
+ };
+
+ @Override
+ public void dumpControllerState(PrintWriter pw) {
+ pw.println("Conn.");
+ pw.println("connected: " + mNetworkConnected + " unmetered: " + mNetworkUnmetered);
+ for (JobStatus js: mTrackedJobs) {
+ pw.println(String.valueOf(js.hashCode()).substring(0, 3) + ".."
+ + ": C=" + js.hasConnectivityConstraint()
+ + ", UM=" + js.hasUnmeteredConstraint());
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/task/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
similarity index 91%
rename from services/core/java/com/android/server/task/controllers/IdleController.java
rename to services/core/java/com/android/server/job/controllers/IdleController.java
index c47faca..07ffe4d 100644
--- a/services/core/java/com/android/server/task/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -14,8 +14,9 @@
* limitations under the License
*/
-package com.android.server.task.controllers;
+package com.android.server.job.controllers;
+import java.io.PrintWriter;
import java.util.ArrayList;
import android.app.AlarmManager;
@@ -28,8 +29,8 @@
import android.os.SystemClock;
import android.util.Slog;
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
public class IdleController extends StateController {
private static final String TAG = "IdleController";
@@ -42,14 +43,14 @@
private static final String ACTION_TRIGGER_IDLE =
"com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE";
- final ArrayList<TaskStatus> mTrackedTasks = new ArrayList<TaskStatus>();
+ final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
IdlenessTracker mIdleTracker;
// Singleton factory
private static Object sCreationLock = new Object();
private static volatile IdleController sController;
- public static IdleController get(TaskManagerService service) {
+ public static IdleController get(JobSchedulerService service) {
synchronized (sCreationLock) {
if (sController == null) {
sController = new IdleController(service, service.getContext());
@@ -67,7 +68,7 @@
* StateController interface
*/
@Override
- public void maybeStartTrackingTask(TaskStatus taskStatus) {
+ public void maybeStartTrackingJob(JobStatus taskStatus) {
if (taskStatus.hasIdleConstraint()) {
synchronized (mTrackedTasks) {
mTrackedTasks.add(taskStatus);
@@ -77,7 +78,7 @@
}
@Override
- public void maybeStopTrackingTask(TaskStatus taskStatus) {
+ public void maybeStopTrackingJob(JobStatus taskStatus) {
synchronized (mTrackedTasks) {
mTrackedTasks.remove(taskStatus);
}
@@ -88,7 +89,7 @@
*/
void reportNewIdleState(boolean isIdle) {
synchronized (mTrackedTasks) {
- for (TaskStatus task : mTrackedTasks) {
+ for (JobStatus task : mTrackedTasks) {
task.idleConstraintSatisfied.set(isIdle);
}
}
@@ -177,4 +178,9 @@
}
}
}
+
+ @Override
+ public void dumpControllerState(PrintWriter pw) {
+
+ }
}
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
new file mode 100644
index 0000000..15a6b25
--- /dev/null
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -0,0 +1,217 @@
+/*
+ * 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.server.job.controllers;
+
+import android.app.job.JobInfo;
+import android.content.ComponentName;
+import android.os.PersistableBundle;
+import android.os.SystemClock;
+import android.os.UserHandle;
+
+import java.io.PrintWriter;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Uniquely identifies a job internally.
+ * Created from the public {@link android.app.job.JobInfo} object when it lands on the scheduler.
+ * Contains current state of the requirements of the job, as well as a function to evaluate
+ * whether it's ready to run.
+ * This object is shared among the various controllers - hence why the different fields are atomic.
+ * This isn't strictly necessary because each controller is only interested in a specific field,
+ * and the receivers that are listening for global state change will all run on the main looper,
+ * but we don't enforce that so this is safer.
+ * @hide
+ */
+public class JobStatus {
+ public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
+ public static final long NO_EARLIEST_RUNTIME = 0L;
+
+ final JobInfo job;
+ final int uId;
+
+ /** At reschedule time we need to know whether to update job on disk. */
+ final boolean persisted;
+
+ // Constraints.
+ final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
+ final AtomicBoolean timeDelayConstraintSatisfied = new AtomicBoolean();
+ final AtomicBoolean deadlineConstraintSatisfied = new AtomicBoolean();
+ final AtomicBoolean idleConstraintSatisfied = new AtomicBoolean();
+ final AtomicBoolean unmeteredConstraintSatisfied = new AtomicBoolean();
+ final AtomicBoolean connectivityConstraintSatisfied = new AtomicBoolean();
+
+ /**
+ * Earliest point in the future at which this job will be eligible to run. A value of 0
+ * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
+ */
+ private long earliestRunTimeElapsedMillis;
+ /**
+ * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
+ * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
+ */
+ private long latestRunTimeElapsedMillis;
+ /** How many times this job has failed, used to compute back-off. */
+ private final int numFailures;
+
+ /** Provide a handle to the service that this job will be run on. */
+ public int getServiceToken() {
+ return uId;
+ }
+
+ private JobStatus(JobInfo job, int uId, boolean persisted, int numFailures) {
+ this.job = job;
+ this.uId = uId;
+ this.numFailures = numFailures;
+ this.persisted = persisted;
+ }
+
+ /** Create a newly scheduled job. */
+ public JobStatus(JobInfo job, int uId, boolean persisted) {
+ this(job, uId, persisted, 0);
+
+ final long elapsedNow = SystemClock.elapsedRealtime();
+
+ if (job.isPeriodic()) {
+ earliestRunTimeElapsedMillis = elapsedNow;
+ latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
+ } else {
+ earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
+ elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
+ latestRunTimeElapsedMillis = job.hasLateConstraint() ?
+ elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
+ }
+ }
+
+ /**
+ * Create a new JobStatus that was loaded from disk. We ignore the provided
+ * {@link android.app.job.JobInfo} time criteria because we can load a persisted periodic job
+ * from the {@link com.android.server.job.JobStore} and still want to respect its
+ * wallclock runtime rather than resetting it on every boot.
+ * We consider a freshly loaded job to no longer be in back-off.
+ */
+ public JobStatus(JobInfo job, int uId, long earliestRunTimeElapsedMillis,
+ long latestRunTimeElapsedMillis) {
+ this(job, uId, true, 0);
+
+ this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
+ this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
+ }
+
+ /** Create a new job to be rescheduled with the provided parameters. */
+ public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
+ long newLatestRuntimeElapsedMillis, int backoffAttempt) {
+ this(rescheduling.job, rescheduling.getUid(), rescheduling.isPersisted(), backoffAttempt);
+
+ earliestRunTimeElapsedMillis = newEarliestRuntimeElapsedMillis;
+ latestRunTimeElapsedMillis = newLatestRuntimeElapsedMillis;
+ }
+
+ public JobInfo getJob() {
+ return job;
+ }
+
+ public int getJobId() {
+ return job.getId();
+ }
+
+ public int getNumFailures() {
+ return numFailures;
+ }
+
+ public ComponentName getServiceComponent() {
+ return job.getService();
+ }
+
+ public int getUserId() {
+ return UserHandle.getUserId(uId);
+ }
+
+ public int getUid() {
+ return uId;
+ }
+
+ public PersistableBundle getExtras() {
+ return job.getExtras();
+ }
+
+ public boolean hasConnectivityConstraint() {
+ return job.getNetworkCapabilities() == JobInfo.NetworkType.ANY;
+ }
+
+ public boolean hasUnmeteredConstraint() {
+ return job.getNetworkCapabilities() == JobInfo.NetworkType.UNMETERED;
+ }
+
+ public boolean hasChargingConstraint() {
+ return job.isRequireCharging();
+ }
+
+ public boolean hasTimingDelayConstraint() {
+ return earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME;
+ }
+
+ public boolean hasDeadlineConstraint() {
+ return latestRunTimeElapsedMillis != NO_LATEST_RUNTIME;
+ }
+
+ public boolean hasIdleConstraint() {
+ return job.isRequireDeviceIdle();
+ }
+
+ public long getEarliestRunTime() {
+ return earliestRunTimeElapsedMillis;
+ }
+
+ public long getLatestRunTimeElapsed() {
+ return latestRunTimeElapsedMillis;
+ }
+
+ public boolean isPersisted() {
+ return persisted;
+ }
+ /**
+ * @return Whether or not this job is ready to run, based on its requirements.
+ */
+ public synchronized boolean isReady() {
+ return (!hasChargingConstraint() || chargingConstraintSatisfied.get())
+ && (!hasTimingDelayConstraint() || timeDelayConstraintSatisfied.get())
+ && (!hasConnectivityConstraint() || connectivityConstraintSatisfied.get())
+ && (!hasUnmeteredConstraint() || unmeteredConstraintSatisfied.get())
+ && (!hasIdleConstraint() || idleConstraintSatisfied.get())
+ // Also ready if the deadline has expired - special case.
+ || (hasDeadlineConstraint() && deadlineConstraintSatisfied.get());
+ }
+
+ public boolean matches(int uid, int jobId) {
+ return this.job.getId() == jobId && this.uId == uid;
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(hashCode()).substring(0, 3) + ".."
+ + ":[" + job.getService().getPackageName() + ",jId=" + job.getId()
+ + ",R=(" + earliestRunTimeElapsedMillis + "," + latestRunTimeElapsedMillis + ")"
+ + ",N=" + job.getNetworkCapabilities() + ",C=" + job.isRequireCharging()
+ + ",I=" + job.isRequireDeviceIdle() + ",F=" + numFailures
+ + (isReady() ? "(READY)" : "")
+ + "]";
+ }
+ // Dumpsys infrastructure
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(this.toString());
+ }
+}
diff --git a/services/core/java/com/android/server/task/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
similarity index 66%
rename from services/core/java/com/android/server/task/controllers/StateController.java
rename to services/core/java/com/android/server/job/controllers/StateController.java
index cbe6ff8..81658bf 100644
--- a/services/core/java/com/android/server/task/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -14,16 +14,18 @@
* limitations under the License
*/
-package com.android.server.task.controllers;
+package com.android.server.job.controllers;
import android.content.Context;
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
+
+import java.io.PrintWriter;
/**
- * Incorporates shared controller logic between the various controllers of the TaskManager.
- * These are solely responsible for tracking a list of tasks, and notifying the TM when these
+ * Incorporates shared controller logic between the various controllers of the JobManager.
+ * These are solely responsible for tracking a list of jobs, and notifying the JM when these
* are ready to run, or whether they must be stopped.
*/
public abstract class StateController {
@@ -37,15 +39,17 @@
}
/**
- * Implement the logic here to decide whether a task should be tracked by this controller.
- * This logic is put here so the TaskManger can be completely agnostic of Controller logic.
+ * 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.
* Also called when updating a task, so implementing controllers have to be aware of
* preexisting tasks.
*/
- public abstract void maybeStartTrackingTask(TaskStatus taskStatus);
+ public abstract void maybeStartTrackingJob(JobStatus jobStatus);
/**
* Remove task - this will happen if the task is cancelled, completed, etc.
*/
- public abstract void maybeStopTrackingTask(TaskStatus taskStatus);
+ public abstract void maybeStopTrackingJob(JobStatus jobStatus);
+
+ public abstract void dumpControllerState(PrintWriter pw);
}
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
new file mode 100644
index 0000000..e46226c
--- /dev/null
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -0,0 +1,289 @@
+/*
+ * 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.server.job.controllers;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.SystemClock;
+import android.util.Slog;
+
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
+
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * This class sets an alarm for the next expiring job, and determines whether a job's minimum
+ * delay has been satisfied.
+ */
+public class TimeController extends StateController {
+ private static final String TAG = "JobScheduler.Time";
+ private static final String ACTION_JOB_EXPIRED =
+ "android.content.jobscheduler.JOB_DEADLINE_EXPIRED";
+ private static final String ACTION_JOB_DELAY_EXPIRED =
+ "android.content.jobscheduler.JOB_DELAY_EXPIRED";
+
+ /** Set an alarm for the next job expiry. */
+ private final PendingIntent mDeadlineExpiredAlarmIntent;
+ /** Set an alarm for the next job delay expiry. This*/
+ private final PendingIntent mNextDelayExpiredAlarmIntent;
+ /** Constant time determining how near in the future we'll set an alarm for. */
+ private static final long MIN_WAKEUP_INTERVAL_MILLIS = 15 * 1000;
+
+ private long mNextJobExpiredElapsedMillis;
+ private long mNextDelayExpiredElapsedMillis;
+
+ private AlarmManager mAlarmService = null;
+ /** List of tracked jobs, sorted asc. by deadline */
+ private final List<JobStatus> mTrackedJobs = new LinkedList<JobStatus>();
+ /** Singleton. */
+ private static TimeController mSingleton;
+
+ public static synchronized TimeController get(JobSchedulerService jms) {
+ if (mSingleton == null) {
+ mSingleton = new TimeController(jms, jms.getContext());
+ }
+ return mSingleton;
+ }
+
+ private TimeController(StateChangedListener stateChangedListener, Context context) {
+ super(stateChangedListener, context);
+ mDeadlineExpiredAlarmIntent =
+ PendingIntent.getBroadcast(mContext, 0 /* ignored */,
+ new Intent(ACTION_JOB_EXPIRED), 0);
+ mNextDelayExpiredAlarmIntent =
+ PendingIntent.getBroadcast(mContext, 0 /* ignored */,
+ new Intent(ACTION_JOB_DELAY_EXPIRED), 0);
+ mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
+ mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
+
+ // Register BR for these intents.
+ IntentFilter intentFilter = new IntentFilter(ACTION_JOB_EXPIRED);
+ intentFilter.addAction(ACTION_JOB_DELAY_EXPIRED);
+ mContext.registerReceiver(mAlarmExpiredReceiver, intentFilter);
+ }
+
+ /**
+ * Check if the job has a timing constraint, and if so determine where to insert it in our
+ * list.
+ */
+ @Override
+ public synchronized void maybeStartTrackingJob(JobStatus job) {
+ if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
+ maybeStopTrackingJob(job);
+ ListIterator<JobStatus> it = mTrackedJobs.listIterator(mTrackedJobs.size());
+ while (it.hasPrevious()) {
+ JobStatus ts = it.previous();
+ if (ts.getLatestRunTimeElapsed() < job.getLatestRunTimeElapsed()) {
+ // Insert
+ break;
+ }
+ }
+ it.add(job);
+ maybeUpdateAlarms(
+ job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
+ job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE);
+ }
+ }
+
+ /**
+ * When we stop tracking a job, we only need to update our alarms if the job we're no longer
+ * tracking was the one our alarms were based off of.
+ * Really an == comparison should be enough, but why play with fate? We'll do <=.
+ */
+ @Override
+ public synchronized void maybeStopTrackingJob(JobStatus job) {
+ if (mTrackedJobs.remove(job)) {
+ checkExpiredDelaysAndResetAlarm();
+ checkExpiredDeadlinesAndResetAlarm();
+ }
+ }
+
+ /**
+ * Determines whether this controller can stop tracking the given job.
+ * The controller is no longer interested in a job once its time constraint is satisfied, and
+ * the job's deadline is fulfilled - unlike other controllers a time constraint can't toggle
+ * back and forth.
+ */
+ private boolean canStopTrackingJob(JobStatus job) {
+ return (!job.hasTimingDelayConstraint() ||
+ job.timeDelayConstraintSatisfied.get()) &&
+ (!job.hasDeadlineConstraint() ||
+ job.deadlineConstraintSatisfied.get());
+ }
+
+ private void ensureAlarmService() {
+ if (mAlarmService == null) {
+ mAlarmService = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ }
+ }
+
+ /**
+ * Checks list of jobs for ones that have an expired deadline, sending them to the JobScheduler
+ * if so, removing them from this list, and updating the alarm for the next expiry time.
+ */
+ private synchronized void checkExpiredDeadlinesAndResetAlarm() {
+ long nextExpiryTime = Long.MAX_VALUE;
+ final long nowElapsedMillis = SystemClock.elapsedRealtime();
+
+ Iterator<JobStatus> it = mTrackedJobs.iterator();
+ while (it.hasNext()) {
+ JobStatus job = it.next();
+ if (!job.hasDeadlineConstraint()) {
+ continue;
+ }
+ final long jobDeadline = job.getLatestRunTimeElapsed();
+
+ if (jobDeadline <= nowElapsedMillis) {
+ job.deadlineConstraintSatisfied.set(true);
+ mStateChangedListener.onRunJobNow(job);
+ it.remove();
+ } else { // Sorted by expiry time, so take the next one and stop.
+ nextExpiryTime = jobDeadline;
+ break;
+ }
+ }
+ setDeadlineExpiredAlarm(nextExpiryTime);
+ }
+
+ /**
+ * Handles alarm that notifies us that a job's delay has expired. Iterates through the list of
+ * tracked jobs and marks them as ready as appropriate.
+ */
+ private synchronized void checkExpiredDelaysAndResetAlarm() {
+ final long nowElapsedMillis = SystemClock.elapsedRealtime();
+ long nextDelayTime = Long.MAX_VALUE;
+ boolean ready = false;
+ Iterator<JobStatus> it = mTrackedJobs.iterator();
+ while (it.hasNext()) {
+ final JobStatus job = it.next();
+ if (!job.hasTimingDelayConstraint()) {
+ continue;
+ }
+ final long jobDelayTime = job.getEarliestRunTime();
+ if (jobDelayTime <= nowElapsedMillis) {
+ job.timeDelayConstraintSatisfied.set(true);
+ if (canStopTrackingJob(job)) {
+ it.remove();
+ }
+ if (job.isReady()) {
+ ready = true;
+ }
+ } else { // Keep going through list to get next delay time.
+ if (nextDelayTime > jobDelayTime) {
+ nextDelayTime = jobDelayTime;
+ }
+ }
+ }
+ if (ready) {
+ mStateChangedListener.onControllerStateChanged();
+ }
+ setDelayExpiredAlarm(nextDelayTime);
+ }
+
+ private void maybeUpdateAlarms(long delayExpiredElapsed, long deadlineExpiredElapsed) {
+ if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
+ setDelayExpiredAlarm(delayExpiredElapsed);
+ }
+ if (deadlineExpiredElapsed < mNextJobExpiredElapsedMillis) {
+ setDeadlineExpiredAlarm(deadlineExpiredElapsed);
+ }
+ }
+
+ /**
+ * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's
+ * delay will expire.
+ * This alarm <b>will not</b> wake up the phone.
+ */
+ private void setDelayExpiredAlarm(long alarmTimeElapsedMillis) {
+ final long earliestWakeupTimeElapsed =
+ SystemClock.elapsedRealtime() + MIN_WAKEUP_INTERVAL_MILLIS;
+ if (alarmTimeElapsedMillis < earliestWakeupTimeElapsed) {
+ alarmTimeElapsedMillis = earliestWakeupTimeElapsed;
+ }
+ mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
+ updateAlarmWithPendingIntent(mNextDelayExpiredAlarmIntent, mNextDelayExpiredElapsedMillis);
+ }
+
+ /**
+ * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's
+ * deadline will expire.
+ * This alarm <b>will</b> wake up the phone.
+ */
+ private void setDeadlineExpiredAlarm(long alarmTimeElapsedMillis) {
+ final long earliestWakeupTimeElapsed =
+ SystemClock.elapsedRealtime() + MIN_WAKEUP_INTERVAL_MILLIS;
+ if (alarmTimeElapsedMillis < earliestWakeupTimeElapsed) {
+ alarmTimeElapsedMillis = earliestWakeupTimeElapsed;
+ }
+ mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
+ updateAlarmWithPendingIntent(mDeadlineExpiredAlarmIntent, mNextJobExpiredElapsedMillis);
+ }
+
+ private void updateAlarmWithPendingIntent(PendingIntent pi, long alarmTimeElapsed) {
+ ensureAlarmService();
+ if (alarmTimeElapsed == Long.MAX_VALUE) {
+ mAlarmService.cancel(pi);
+ } else {
+ if (DEBUG) {
+ Slog.d(TAG, "Setting " + pi.getIntent().getAction() + " for: " + alarmTimeElapsed);
+ }
+ mAlarmService.set(AlarmManager.ELAPSED_REALTIME, alarmTimeElapsed, pi);
+ }
+ }
+
+ private final BroadcastReceiver mAlarmExpiredReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) {
+ Slog.d(TAG, "Just received alarm: " + intent.getAction());
+ }
+ // A job has just expired, so we run through the list of jobs that we have and
+ // notify our StateChangedListener.
+ if (ACTION_JOB_EXPIRED.equals(intent.getAction())) {
+ checkExpiredDeadlinesAndResetAlarm();
+ } else if (ACTION_JOB_DELAY_EXPIRED.equals(intent.getAction())) {
+ checkExpiredDelaysAndResetAlarm();
+ }
+ }
+ };
+
+ @Override
+ public void dumpControllerState(PrintWriter pw) {
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ pw.println("Alarms (" + SystemClock.elapsedRealtime() + ")");
+ pw.println(
+ "Next delay alarm in " + (mNextDelayExpiredElapsedMillis - nowElapsed)/1000 + "s");
+ pw.println("Next deadline alarm in " + (mNextJobExpiredElapsedMillis - nowElapsed)/1000
+ + "s");
+ pw.println("Tracking:");
+ for (JobStatus ts : mTrackedJobs) {
+ pw.println(String.valueOf(ts.hashCode()).substring(0, 3) + ".."
+ + ": (" + (ts.hasTimingDelayConstraint() ? ts.getEarliestRunTime() : "N/A")
+ + ", " + (ts.hasDeadlineConstraint() ?ts.getLatestRunTimeElapsed() : "N/A")
+ + ")");
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index c6cf68f..c5b6c7b 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -83,6 +83,8 @@
import java.util.Date;
import java.util.Map.Entry;
import java.util.Properties;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
/**
* A GPS implementation of LocationProvider used by LocationManager.
@@ -158,6 +160,12 @@
private static final int AGPS_TYPE_SUPL = 1;
private static final int AGPS_TYPE_C2K = 2;
+ // these must match the definitions in gps.h
+ private static final int APN_INVALID = 0;
+ private static final int APN_IPV4 = 1;
+ private static final int APN_IPV6 = 2;
+ private static final int APN_IPV4V6 = 3;
+
// for mAGpsDataConnectionState
private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
private static final int AGPS_DATA_CONNECTION_OPENING = 1;
@@ -312,8 +320,9 @@
private Handler mHandler;
private String mAGpsApn;
+ private int mApnIpType;
private int mAGpsDataConnectionState;
- private int mAGpsDataConnectionIpAddr;
+ private InetAddress mAGpsDataConnectionIpAddr;
private final ConnectivityManager mConnMgr;
private final GpsNetInitiatedHandler mNIHandler;
@@ -595,28 +604,28 @@
if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL
&& mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
- String apnName = info.getExtraInfo();
if (mNetworkAvailable) {
+ String apnName = info.getExtraInfo();
if (apnName == null) {
/* Assign a dummy value in the case of C2K as otherwise we will have a runtime
exception in the following call to native_agps_data_conn_open*/
apnName = "dummy-apn";
}
mAGpsApn = apnName;
- if (DEBUG) Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr);
- if (mAGpsDataConnectionIpAddr != 0xffffffff) {
- boolean route_result;
- if (DEBUG) Log.d(TAG, "call requestRouteToHost");
- route_result = mConnMgr.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_SUPL,
- mAGpsDataConnectionIpAddr);
- if (route_result == false) Log.d(TAG, "call requestRouteToHost failed");
+ mApnIpType = getApnIpType(apnName);
+ setRouting();
+ if (DEBUG) {
+ String message = String.format(
+ "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
+ mAGpsApn, mApnIpType);
+ Log.d(TAG, message);
}
- if (DEBUG) Log.d(TAG, "call native_agps_data_conn_open");
- native_agps_data_conn_open(apnName);
+ native_agps_data_conn_open(mAGpsApn, mApnIpType);
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
} else {
- if (DEBUG) Log.d(TAG, "call native_agps_data_conn_failed");
+ Log.e(TAG, "call native_agps_data_conn_failed, info: " + info);
mAGpsApn = null;
+ mApnIpType = APN_INVALID;
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
native_agps_data_conn_failed();
}
@@ -1324,7 +1333,7 @@
/**
* called from native code to update AGPS status
*/
- private void reportAGpsStatus(int type, int status, int ipaddr) {
+ private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
switch (status) {
case GPS_REQUEST_AGPS_DATA_CONN:
if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
@@ -1333,20 +1342,20 @@
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
int result = mConnMgr.startUsingNetworkFeature(
ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
- mAGpsDataConnectionIpAddr = ipaddr;
+ if (ipaddr != null) {
+ try {
+ mAGpsDataConnectionIpAddr = InetAddress.getByAddress(ipaddr);
+ } catch (UnknownHostException e) {
+ Log.e(TAG, "Bad IP Address: " + ipaddr, e);
+ mAGpsDataConnectionIpAddr = null;
+ }
+ }
+
if (result == PhoneConstants.APN_ALREADY_ACTIVE) {
if (DEBUG) Log.d(TAG, "PhoneConstants.APN_ALREADY_ACTIVE");
if (mAGpsApn != null) {
- Log.d(TAG, "mAGpsDataConnectionIpAddr " + mAGpsDataConnectionIpAddr);
- if (mAGpsDataConnectionIpAddr != 0xffffffff) {
- boolean route_result;
- if (DEBUG) Log.d(TAG, "call requestRouteToHost");
- route_result = mConnMgr.requestRouteToHost(
- ConnectivityManager.TYPE_MOBILE_SUPL,
- mAGpsDataConnectionIpAddr);
- if (route_result == false) Log.d(TAG, "call requestRouteToHost failed");
- }
- native_agps_data_conn_open(mAGpsApn);
+ setRouting();
+ native_agps_data_conn_open(mAGpsApn, mApnIpType);
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
} else {
Log.e(TAG, "mAGpsApn not set when receiving PhoneConstants.APN_ALREADY_ACTIVE");
@@ -1370,6 +1379,7 @@
ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
native_agps_data_conn_closed();
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
+ mAGpsDataConnectionIpAddr = null;
}
break;
case GPS_AGPS_DATA_CONNECTED:
@@ -1821,21 +1831,97 @@
private String getSelectedApn() {
Uri uri = Uri.parse("content://telephony/carriers/preferapn");
- String apn = null;
-
- Cursor cursor = mContext.getContentResolver().query(uri, new String[] {"apn"},
- null, null, Carriers.DEFAULT_SORT_ORDER);
-
- if (null != cursor) {
- try {
- if (cursor.moveToFirst()) {
- apn = cursor.getString(0);
- }
- } finally {
+ Cursor cursor = null;
+ try {
+ cursor = mContext.getContentResolver().query(
+ uri,
+ new String[] { "apn" },
+ null /* selection */,
+ null /* selectionArgs */,
+ Carriers.DEFAULT_SORT_ORDER);
+ if (cursor != null && cursor.moveToFirst()) {
+ return cursor.getString(0);
+ } else {
+ Log.e(TAG, "No APN found to select.");
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error encountered on selectiong the APN.", e);
+ } finally {
+ if (cursor != null) {
cursor.close();
}
}
- return apn;
+
+ return null;
+ }
+
+ private int getApnIpType(String apn) {
+ if (apn == null) {
+ return APN_INVALID;
+ }
+
+ // look for cached data to use
+ if (apn.equals(mAGpsApn) && mApnIpType != APN_INVALID) {
+ return mApnIpType;
+ }
+
+ String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
+ Cursor cursor = null;
+ try {
+ cursor = mContext.getContentResolver().query(
+ Carriers.CONTENT_URI,
+ new String[] { Carriers.PROTOCOL },
+ selection,
+ null,
+ Carriers.DEFAULT_SORT_ORDER);
+
+ if (null != cursor && cursor.moveToFirst()) {
+ return translateToApnIpType(cursor.getString(0), apn);
+ } else {
+ Log.e(TAG, "No entry found in query for APN: " + apn);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error encountered on APN query for: " + apn, e);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+
+ return APN_INVALID;
+ }
+
+ private int translateToApnIpType(String ipProtocol, String apn) {
+ if ("IP".equals(ipProtocol)) {
+ return APN_IPV4;
+ }
+ if ("IPV6".equals(ipProtocol)) {
+ return APN_IPV6;
+ }
+ if ("IPV4V6".equals(ipProtocol)) {
+ return APN_IPV4V6;
+ }
+
+ // we hit the default case so the ipProtocol is not recognized
+ String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
+ Log.e(TAG, message);
+ return APN_INVALID;
+ }
+
+ private void setRouting() {
+ if (mAGpsDataConnectionIpAddr == null) {
+ return;
+ }
+
+ boolean result = mConnMgr.requestRouteToHostAddress(
+ ConnectivityManager.TYPE_MOBILE_SUPL,
+ mAGpsDataConnectionIpAddr);
+
+ if (!result) {
+ Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
+ } else if (DEBUG) {
+ Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
+ }
}
@Override
@@ -1897,7 +1983,7 @@
private native String native_get_internal_state();
// AGPS Support
- private native void native_agps_data_conn_open(String apn);
+ private native void native_agps_data_conn_open(String apn, int apnIpType);
private native void native_agps_data_conn_closed();
private native void native_agps_data_conn_failed();
private native void native_agps_ni_message(byte [] msg, int length);
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 737ffda..9ae8aed 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -130,7 +130,8 @@
mOwnerPid = ownerPid;
mOwnerUid = ownerUid;
mUserId = userId;
- mSessionInfo = new MediaSessionInfo(UUID.randomUUID().toString(), ownerPackageName);
+ mSessionInfo = new MediaSessionInfo(UUID.randomUUID().toString(), ownerPackageName,
+ ownerPid);
mTag = tag;
mController = new ControllerStub();
mSession = new SessionStub();
@@ -943,6 +944,16 @@
}
@Override
+ public MediaSessionInfo getSessionInfo() {
+ return mSessionInfo;
+ }
+
+ @Override
+ public long getFlags() {
+ return mFlags;
+ }
+
+ @Override
public void play() throws RemoteException {
mSessionCb.play();
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 87665e1..67065ba 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -29,9 +29,11 @@
import android.media.AudioManager;
import android.media.IAudioService;
import android.media.routeprovider.RouteRequest;
+import android.media.session.IActiveSessionsListener;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
import android.media.session.ISessionManager;
+import android.media.session.MediaSessionToken;
import android.media.session.RouteInfo;
import android.media.session.RouteOptions;
import android.media.session.MediaSession;
@@ -39,6 +41,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -75,10 +78,12 @@
private final ArrayList<MediaSessionRecord> mAllSessions = new ArrayList<MediaSessionRecord>();
private final SparseArray<UserRecord> mUserRecords = new SparseArray<UserRecord>();
+ private final ArrayList<SessionsListenerRecord> mSessionsListeners
+ = new ArrayList<SessionsListenerRecord>();
// private final ArrayList<MediaRouteProviderProxy> mProviders
// = new ArrayList<MediaRouteProviderProxy>();
private final Object mLock = new Object();
- private final Handler mHandler = new Handler();
+ private final MessageHandler mHandler = new MessageHandler();
private final PowerManager.WakeLock mMediaEventWakeLock;
private KeyguardManager mKeyguardManager;
@@ -200,15 +205,20 @@
}
}
}
+ mHandler.post(MessageHandler.MSG_SESSIONS_CHANGED, record.getUserId(), 0);
}
public void onSessionPlaystateChange(MediaSessionRecord record, int oldState, int newState) {
+ boolean updateSessions = false;
synchronized (mLock) {
if (!mAllSessions.contains(record)) {
Log.d(TAG, "Unknown session changed playback state. Ignoring.");
return;
}
- mPriorityStack.onPlaystateChange(record, oldState, newState);
+ updateSessions = mPriorityStack.onPlaystateChange(record, oldState, newState);
+ }
+ if (updateSessions) {
+ mHandler.post(MessageHandler.MSG_SESSIONS_CHANGED, record.getUserId(), 0);
}
}
@@ -315,6 +325,8 @@
// ignore exceptions while destroying a session.
}
session.onDestroy();
+
+ mHandler.post(MessageHandler.MSG_SESSIONS_CHANGED, session.getUserId(), 0);
}
private void enforcePackageName(String packageName, int uid) {
@@ -428,6 +440,8 @@
UserRecord user = getOrCreateUser(userId);
user.addSessionLocked(session);
+ mHandler.post(MessageHandler.MSG_SESSIONS_CHANGED, userId, 0);
+
if (DEBUG) {
Log.d(TAG, "Created session for package " + callerPackageName + " with tag " + tag);
}
@@ -453,11 +467,43 @@
return -1;
}
+ private int findIndexOfSessionsListenerLocked(IActiveSessionsListener listener) {
+ for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
+ if (mSessionsListeners.get(i).mListener == listener) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
private boolean isSessionDiscoverable(MediaSessionRecord record) {
// TODO probably want to check more than if it's active.
return record.isActive();
}
+ private void pushSessionsChanged(int userId) {
+ synchronized (mLock) {
+ List<MediaSessionRecord> records = mPriorityStack.getActiveSessions(userId);
+ int size = records.size();
+ ArrayList<MediaSessionToken> tokens = new ArrayList<MediaSessionToken>();
+ for (int i = 0; i < size; i++) {
+ tokens.add(new MediaSessionToken(records.get(i).getControllerBinder()));
+ }
+ for (int i = mSessionsListeners.size() - 1; i >= 0; i--) {
+ SessionsListenerRecord record = mSessionsListeners.get(i);
+ if (record.mUserId == UserHandle.USER_ALL || record.mUserId == userId) {
+ try {
+ record.mListener.onActiveSessionsChanged(tokens);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Dead ActiveSessionsListener in pushSessionsChanged, removing",
+ e);
+ mSessionsListeners.remove(i);
+ }
+ }
+ }
+ }
+ }
+
private MediaRouteProviderProxy.RoutesListener mRoutesCallback
= new MediaRouteProviderProxy.RoutesListener() {
@Override
@@ -613,6 +659,23 @@
};
}
+ final class SessionsListenerRecord implements IBinder.DeathRecipient {
+ private final IActiveSessionsListener mListener;
+ private final int mUserId;
+
+ public SessionsListenerRecord(IActiveSessionsListener listener, int userId) {
+ mListener = listener;
+ mUserId = userId;
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ mSessionsListeners.remove(this);
+ }
+ }
+ }
+
class SessionManagerImpl extends ISessionManager.Stub {
private static final String EXTRA_WAKELOCK_ACQUIRED =
"android.media.AudioService.WAKELOCK_ACQUIRED";
@@ -648,20 +711,7 @@
final long token = Binder.clearCallingIdentity();
try {
- String packageName = null;
- if (componentName != null) {
- // If they gave us a component name verify they own the
- // package
- packageName = componentName.getPackageName();
- enforcePackageName(packageName, uid);
- }
- // Check that they can make calls on behalf of the user and
- // get the final user id
- int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
- true /* allowAll */, true /* requireFull */, "getSessions", packageName);
- // Check if they have the permissions or their component is
- // enabled for the user they're calling from.
- enforceMediaPermissions(componentName, pid, uid, resolvedUserId);
+ int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
ArrayList<IBinder> binders = new ArrayList<IBinder>();
synchronized (mLock) {
ArrayList<MediaSessionRecord> records = mPriorityStack
@@ -677,6 +727,52 @@
}
}
+ @Override
+ public void addSessionsListener(IActiveSessionsListener listener,
+ ComponentName componentName, int userId) throws RemoteException {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+
+ try {
+ int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
+ synchronized (mLock) {
+ int index = findIndexOfSessionsListenerLocked(listener);
+ if (index != -1) {
+ Log.w(TAG, "ActiveSessionsListener is already added, ignoring");
+ return;
+ }
+ SessionsListenerRecord record = new SessionsListenerRecord(listener,
+ resolvedUserId);
+ try {
+ listener.asBinder().linkToDeath(record, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "ActiveSessionsListener is dead, ignoring it", e);
+ return;
+ }
+ mSessionsListeners.add(record);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void removeSessionsListener(IActiveSessionsListener listener)
+ throws RemoteException {
+ synchronized (mLock) {
+ int index = findIndexOfSessionsListenerLocked(listener);
+ if (index != -1) {
+ SessionsListenerRecord record = mSessionsListeners.remove(index);
+ try {
+ record.mListener.asBinder().unlinkToDeath(record, 0);
+ } catch (Exception e) {
+ // ignore exceptions, the record is being removed
+ }
+ }
+ }
+ }
+
/**
* Handles the dispatching of the media button events to one of the
* registered listeners, or if there was none, broadcast an
@@ -764,6 +860,25 @@
}
}
+ private int verifySessionsRequest(ComponentName componentName, int userId, final int pid,
+ final int uid) {
+ String packageName = null;
+ if (componentName != null) {
+ // If they gave us a component name verify they own the
+ // package
+ packageName = componentName.getPackageName();
+ enforcePackageName(packageName, uid);
+ }
+ // Check that they can make calls on behalf of the user and
+ // get the final user id
+ int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+ true /* allowAll */, true /* requireFull */, "getSessions", packageName);
+ // Check if they have the permissions or their component is
+ // enabled for the user they're calling from.
+ enforceMediaPermissions(componentName, pid, uid, resolvedUserId);
+ return resolvedUserId;
+ }
+
private void dispatchAdjustVolumeByLocked(int suggestedStream, int delta, int flags,
MediaSessionRecord session) {
int direction = 0;
@@ -781,25 +896,36 @@
}
if (session == null) {
- for (int i = 0; i < steps; i++) {
- try {
- mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
- flags, getContext().getOpPackageName());
- } catch (RemoteException e) {
- Log.e(TAG, "Error adjusting default volume.", e);
+ try {
+ if (delta == 0) {
+ mAudioService.adjustSuggestedStreamVolume(delta, suggestedStream, flags,
+ getContext().getOpPackageName());
+ } else {
+ for (int i = 0; i < steps; i++) {
+ mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
+ flags, getContext().getOpPackageName());
+ }
}
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error adjusting default volume.", e);
}
} else {
if (session.getPlaybackType() == MediaSession.VOLUME_TYPE_LOCAL) {
- for (int i = 0; i < steps; i++) {
- try {
- mAudioService.adjustSuggestedStreamVolume(direction,
+ try {
+ if (delta == 0) {
+ mAudioService.adjustSuggestedStreamVolume(delta,
session.getAudioStream(), flags,
getContext().getOpPackageName());
- } catch (RemoteException e) {
- Log.e(TAG, "Error adjusting volume for stream "
- + session.getAudioStream(), e);
+ } else {
+ for (int i = 0; i < steps; i++) {
+ mAudioService.adjustSuggestedStreamVolume(direction,
+ session.getAudioStream(), flags,
+ getContext().getOpPackageName());
+ }
}
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error adjusting volume for stream "
+ + session.getAudioStream(), e);
}
} else if (session.getPlaybackType() == MediaSession.VOLUME_TYPE_REMOTE) {
session.adjustVolumeBy(delta);
@@ -994,4 +1120,20 @@
};
}
+ final class MessageHandler extends Handler {
+ private static final int MSG_SESSIONS_CHANGED = 1;
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SESSIONS_CHANGED:
+ pushSessionsChanged(msg.arg1);
+ break;
+ }
+ }
+
+ public void post(int what, int arg1, int arg2) {
+ obtainMessage(what, arg1, arg2).sendToTarget();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 803dee2..144ccfa 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -88,16 +88,19 @@
* @param record The record that changed.
* @param oldState Its old playback state.
* @param newState Its new playback state.
+ * @return true if the priority order was updated, false otherwise.
*/
- public void onPlaystateChange(MediaSessionRecord record, int oldState, int newState) {
+ public boolean onPlaystateChange(MediaSessionRecord record, int oldState, int newState) {
if (shouldUpdatePriority(oldState, newState)) {
mSessions.remove(record);
mSessions.add(0, record);
clearCache();
+ return true;
} else if (newState == PlaybackState.STATE_PAUSED) {
// Just clear the volume cache in this case
mCachedVolumeDefault = null;
}
+ return false;
}
/**
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index aee7679..907eeb2 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -81,15 +81,15 @@
for (LinkAddress linkAddr : linkProperties.getLinkAddresses()) {
out.writeUTF(LINK_ADDRESS_KEY);
out.writeUTF(linkAddr.getAddress().getHostAddress());
- out.writeInt(linkAddr.getNetworkPrefixLength());
+ out.writeInt(linkAddr.getPrefixLength());
}
for (RouteInfo route : linkProperties.getRoutes()) {
out.writeUTF(GATEWAY_KEY);
- LinkAddress dest = route.getDestination();
+ LinkAddress dest = route.getDestinationLinkAddress();
if (dest != null) {
out.writeInt(1);
out.writeUTF(dest.getAddress().getHostAddress());
- out.writeInt(dest.getNetworkPrefixLength());
+ out.writeInt(dest.getPrefixLength());
} else {
out.writeInt(0);
}
@@ -100,7 +100,7 @@
out.writeInt(0);
}
}
- for (InetAddress inetAddr : linkProperties.getDnses()) {
+ for (InetAddress inetAddr : linkProperties.getDnsServers()) {
out.writeUTF(DNS_KEY);
out.writeUTF(inetAddr.getHostAddress());
}
@@ -232,7 +232,7 @@
}
linkProperties.addRoute(new RouteInfo(dest, gateway));
} else if (key.equals(DNS_KEY)) {
- linkProperties.addDns(
+ linkProperties.addDnsServer(
NetworkUtils.numericToInetAddress(in.readUTF()));
} else if (key.equals(PROXY_SETTINGS_KEY)) {
proxySettings = ProxySettings.valueOf(in.readUTF());
diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java
index b30baea..6cd4019 100644
--- a/services/core/java/com/android/server/notification/NotificationComparator.java
+++ b/services/core/java/com/android/server/notification/NotificationComparator.java
@@ -41,6 +41,6 @@
return -1 * Float.compare(leftPeple, rightPeople);
}
// then break ties by time, most recent first
- return -1 * Long.compare(lhs.sbn.getPostTime(), rhs.sbn.getPostTime());
+ return -1 * Long.compare(lhs.getRankingTimeMs(), rhs.getRankingTimeMs());
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 386402b..825dc84 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -188,6 +188,8 @@
private AppOpsManager mAppOps;
+ private Archive mArchive;
+
// Notification control database. For now just contains disabled packages.
private AtomicFile mPolicyFile;
private HashSet<String> mBlockedPackages = new HashSet<String>();
@@ -223,10 +225,12 @@
private static final int REASON_LISTENER_CANCEL_ALL = 11;
private static class Archive {
- static final int BUFFER_SIZE = 250;
- ArrayDeque<StatusBarNotification> mBuffer = new ArrayDeque<StatusBarNotification>(BUFFER_SIZE);
+ final int mBufferSize;
+ final ArrayDeque<StatusBarNotification> mBuffer;
- public Archive() {
+ public Archive(int size) {
+ mBufferSize = size;
+ mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
}
public String toString() {
@@ -240,7 +244,7 @@
}
public void record(StatusBarNotification nr) {
- if (mBuffer.size() == BUFFER_SIZE) {
+ if (mBuffer.size() == mBufferSize) {
mBuffer.removeFirst();
}
@@ -250,7 +254,6 @@
mBuffer.addLast(nr.cloneLight());
}
-
public void clear() {
mBuffer.clear();
}
@@ -300,7 +303,7 @@
}
public StatusBarNotification[] getArray(int count) {
- if (count == 0) count = Archive.BUFFER_SIZE;
+ if (count == 0) count = mBufferSize;
final StatusBarNotification[] a
= new StatusBarNotification[Math.min(count, mBuffer.size())];
Iterator<StatusBarNotification> iter = descendingIterator();
@@ -312,7 +315,7 @@
}
public StatusBarNotification[] getArray(int count, String pkg, int userId) {
- if (count == 0) count = Archive.BUFFER_SIZE;
+ if (count == 0) count = mBufferSize;
final StatusBarNotification[] a
= new StatusBarNotification[Math.min(count, mBuffer.size())];
Iterator<StatusBarNotification> iter = filter(descendingIterator(), pkg, userId);
@@ -325,8 +328,6 @@
}
- Archive mArchive = new Archive();
-
private void loadPolicyFile() {
synchronized(mPolicyFile) {
mBlockedPackages.clear();
@@ -854,6 +855,9 @@
}
}
+ mArchive = new Archive(resources.getInteger(
+ R.integer.config_notificationServiceArchiveSize));
+
publishBinderService(Context.NOTIFICATION_SERVICE, mService);
publishLocalService(NotificationManagerInternal.class, mInternalService);
}
@@ -2264,16 +2268,15 @@
// lock on mNotificationList
int indexOfNotificationLocked(String key) {
- NotificationRecord r = mNotificationsByKey.get(key);
- if (r == null) {
- return -1;
+ final int N = mNotificationList.size();
+ for (int i = 0; i < N; i++) {
+ if (key.equals(mNotificationList.get(i).getKey())) {
+ return i;
+ }
}
- int index = Collections.binarySearch(mNotificationList, r, mRankingComparator);
- // Guarantee to return -1 when not found.
- return (index >= 0) ? index : -1;
+ return -1;
}
-
private void updateNotificationPulse() {
synchronized (mNotificationList) {
updateLightsLocked();
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 30d4fec..13fb986 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -54,6 +54,9 @@
// InterceptedNotifications needs to know if this has been previously evaluated.
private boolean mTouchedByZen;
+ // The timestamp used for ranking.
+ private long mRankingTimeMs;
+
// Is this record an update of an old record?
public boolean isUpdate;
@@ -61,6 +64,7 @@
{
this.sbn = sbn;
this.score = score;
+ mRankingTimeMs = calculateRankingTimeMs(0L);
}
// copy any notes that the ranking system may have made before the update
@@ -69,6 +73,7 @@
mRecentlyIntrusive = previous.mRecentlyIntrusive;
mTouchedByZen = previous.mTouchedByZen;
mIntercept = previous.mIntercept;
+ mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
}
public Notification getNotification() { return sbn.getNotification(); }
@@ -139,6 +144,7 @@
pw.println(prefix + " mContactAffinity=" + mContactAffinity);
pw.println(prefix + " mRecentlyIntrusive=" + mRecentlyIntrusive);
pw.println(prefix + " mIntercept=" + mIntercept);
+ pw.println(prefix + " mRankingTimeMs=" + mRankingTimeMs);
}
@@ -206,4 +212,29 @@
mTouchedByZen = true;
}
+ /**
+ * Returns the timestamp to use for time-based sorting in the ranker.
+ */
+ public long getRankingTimeMs() {
+ return mRankingTimeMs;
+ }
+
+ /**
+ * @param previousRankingTimeMs for updated notifications, {@link #getRankingTimeMs()}
+ * of the previous notification record, 0 otherwise
+ */
+ private long calculateRankingTimeMs(long previousRankingTimeMs) {
+ Notification n = getNotification();
+ // Take developer provided 'when', unless it's in the future.
+ if (n.when != 0 && n.when <= sbn.getPostTime()) {
+ return n.when;
+ }
+ // If we've ranked a previous instance with a timestamp, inherit it. This case is
+ // important in order to have ranking stability for updating notifications.
+ if (previousRankingTimeMs > 0) {
+ return previousRankingTimeMs;
+ }
+ return sbn.getPostTime();
+ }
+
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 50a32c4..b95db9c 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -18,6 +18,7 @@
import android.app.AlarmManager;
import android.app.AppOpsManager;
+import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -88,6 +89,10 @@
private static final Set<String> ALARM_PACKAGES = new HashSet<String>(Arrays.asList(
"com.google.android.deskclock"
));
+ private static final Set<String> SYSTEM_PACKAGES = new HashSet<String>(Arrays.asList(
+ "android",
+ "com.android.systemui"
+ ));
public ZenModeHelper(Context context, Handler handler) {
mContext = context;
@@ -130,6 +135,9 @@
// notifications never transition from not intercepted to intercepted
return false;
}
+ if (isSystem(record)) {
+ return false;
+ }
if (isAlarm(record)) {
return false;
}
@@ -239,6 +247,11 @@
}
}
+ private boolean isSystem(NotificationRecord record) {
+ return SYSTEM_PACKAGES.contains(record.sbn.getPackageName())
+ && Notification.CATEGORY_SYSTEM.equals(record.getNotification().category);
+ }
+
private boolean isAlarm(NotificationRecord record) {
return ALARM_PACKAGES.contains(record.sbn.getPackageName());
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index f2db791..2a7b4f6 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -16,12 +16,13 @@
package com.android.server.pm;
-import android.content.BroadcastReceiver;
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.os.ServiceManager;
-import android.os.UserHandle;
import android.util.Log;
import java.util.HashSet;
@@ -30,62 +31,63 @@
/**
* {@hide}
*/
-public class BackgroundDexOptService {
-
+public class BackgroundDexOptService extends JobService {
static final String TAG = "BackgroundDexOptService";
- private final BroadcastReceiver mIdleMaintenanceReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)) {
- onIdleStart();
- } else if (Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) {
- onIdleStop();
- }
- }
- };
-
- final PackageManagerService mPackageManager;
+ static final int BACKGROUND_DEXOPT_JOB = 808;
+ private static ComponentName sDexoptServiceName = new ComponentName(
+ BackgroundDexOptService.class.getPackage().getName(),
+ BackgroundDexOptService.class.getName());
final AtomicBoolean mIdleTime = new AtomicBoolean(false);
- public BackgroundDexOptService(Context context) {
- mPackageManager = (PackageManagerService)ServiceManager.getService("package");
-
- IntentFilter idleMaintenanceFilter = new IntentFilter();
- idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START);
- idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_END);
- context.registerReceiverAsUser(mIdleMaintenanceReceiver, UserHandle.ALL,
- idleMaintenanceFilter, null, null);
+ public static void schedule(Context context) {
+ JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ JobInfo job = new JobInfo.Builder(BACKGROUND_DEXOPT_JOB, sDexoptServiceName)
+ .setRequiresDeviceIdle(true)
+ .setRequiresCharging(true)
+ .build();
+ js.schedule(job);
}
- public boolean onIdleStart() {
+ @Override
+ public boolean onStartJob(JobParameters params) {
Log.i(TAG, "onIdleStart");
- if (mPackageManager.isStorageLow()) {
+ final PackageManagerService pm =
+ (PackageManagerService)ServiceManager.getService("package");
+
+ if (pm.isStorageLow()) {
return false;
}
- final HashSet<String> pkgs = mPackageManager.getPackagesThatNeedDexOpt();
+ final HashSet<String> pkgs = pm.getPackagesThatNeedDexOpt();
if (pkgs == null) {
return false;
}
+
+ final JobParameters jobParams = params;
mIdleTime.set(true);
new Thread("BackgroundDexOptService_DexOpter") {
@Override
public void run() {
for (String pkg : pkgs) {
if (!mIdleTime.get()) {
- break;
+ // stopped while still working, so we need to reschedule
+ schedule(BackgroundDexOptService.this);
+ return;
}
- mPackageManager.performDexOpt(pkg, false);
+ pm.performDexOpt(pkg, false);
}
+ // ran to completion, so we abandon our timeslice and do not reschedule
+ jobFinished(jobParams, false);
}
}.start();
return true;
}
- public void onIdleStop() {
+ @Override
+ public boolean onStopJob(JobParameters params) {
Log.i(TAG, "onIdleStop");
mIdleTime.set(false);
+ return false;
}
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 82d3f53..c0f1eec 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -345,6 +345,10 @@
}
}
+ public int pruneDexCache() {
+ return execute("prunedexcache");
+ }
+
public int freeCache(long freeStorageSize) {
StringBuilder builder = new StringBuilder("freecache");
builder.append(' ');
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 3ed73f7..dd33771 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -28,7 +28,7 @@
import android.content.pm.PackageInstallerParams;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageLite;
+import android.content.pm.PackageParser.ApkLite;
import android.content.pm.Signature;
import android.os.Build;
import android.os.Bundle;
@@ -297,7 +297,7 @@
// Verify that all staged packages are internally consistent
for (File file : files) {
- final PackageLite info = PackageParser.parsePackageLite(file.getAbsolutePath(),
+ final ApkLite info = PackageParser.parseApkLite(file.getAbsolutePath(),
PackageParser.PARSE_GET_SIGNATURES);
if (info == null) {
throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
@@ -356,7 +356,7 @@
"Missing existing base package for " + mPackageName);
}
- final PackageLite info = PackageParser.parsePackageLite(app.sourceDir,
+ final ApkLite info = PackageParser.parseApkLite(app.sourceDir,
PackageParser.PARSE_GET_SIGNATURES);
if (info == null) {
throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8585b4e..8d94396 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -93,6 +93,7 @@
import android.content.pm.PackageInstallerParams;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser.ActivityIntentInfo;
+import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageParser;
import android.content.pm.PackageStats;
import android.content.pm.PackageUserState;
@@ -136,6 +137,7 @@
import android.system.Os;
import android.system.StructStat;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.DisplayMetrics;
import android.util.EventLog;
@@ -412,9 +414,6 @@
final HashMap<String, SharedLibraryEntry> mSharedLibraries
= new HashMap<String, SharedLibraryEntry>();
- // Temporary for building the final shared libraries for an .apk.
- String[] mTmpSharedLibraries = null;
-
// These are the features this devices supports that were read from the
// etc/permissions.xml file.
final HashMap<String, FeatureInfo> mAvailableFeatures =
@@ -1485,7 +1484,21 @@
}
if (didDexOptLibraryOrTool) {
- pruneDexFiles(new File(dataDir, "dalvik-cache"));
+ // If we dexopted a library or tool, then something on the system has
+ // changed. Consider this significant, and wipe away all other
+ // existing dexopt files to ensure we don't leave any dangling around.
+ //
+ // Additionally, delete all dex files from the root directory
+ // since there shouldn't be any there anyway.
+ //
+ // TODO: This should be revisited because it isn't as good an indicator
+ // as it used to be. It used to include the boot classpath but at some point
+ // DexFile.isDexOptNeeded started returning false for the boot
+ // class path files in all cases. It is very possible in a
+ // small maintenance release update that the library and tool
+ // jars may be unchanged but APK could be removed resulting in
+ // unused dalvik-cache files.
+ mInstaller.pruneDexCache();
}
// Collect vendor overlay packages.
@@ -1727,45 +1740,6 @@
Runtime.getRuntime().gc();
}
- private static void pruneDexFiles(File cacheDir) {
- // If we had to do a dexopt of one of the previous
- // things, then something on the system has changed.
- // Consider this significant, and wipe away all other
- // existing dexopt files to ensure we don't leave any
- // dangling around.
- //
- // Additionally, delete all dex files from the root directory
- // since there shouldn't be any there anyway.
- //
- // Note: This isn't as good an indicator as it used to be. It
- // used to include the boot classpath but at some point
- // DexFile.isDexOptNeeded started returning false for the boot
- // class path files in all cases. It is very possible in a
- // small maintenance release update that the library and tool
- // jars may be unchanged but APK could be removed resulting in
- // unused dalvik-cache files.
- File[] files = cacheDir.listFiles();
- if (files != null) {
- for (File file : files) {
- if (!file.isDirectory()) {
- Slog.i(TAG, "Pruning dalvik file: " + file.getAbsolutePath());
- file.delete();
- } else {
- File[] subDirList = file.listFiles();
- if (subDirList != null) {
- for (File subDirFile : subDirList) {
- final String fn = subDirFile.getName();
- if (fn.startsWith("data@app@") || fn.startsWith("data@app-private@")) {
- Slog.i(TAG, "Pruning dalvik file: " + fn);
- subDirFile.delete();
- }
- }
- }
- }
- }
- }
- }
-
@Override
public boolean isFirstBoot() {
return !mRestoredSettings || mPackageUsage.isFirstBoot();
@@ -2268,8 +2242,7 @@
if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) {
return null;
}
- // TODO: teach about reading split name
- pkg = new PackageParser.Package(packageName, null);
+ pkg = new PackageParser.Package(packageName);
pkg.applicationInfo.packageName = packageName;
pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
@@ -4097,19 +4070,19 @@
private boolean createIdmapForPackagePairLI(PackageParser.Package pkg,
PackageParser.Package opkg) {
if (!opkg.mTrustedOverlay) {
- Slog.w(TAG, "Skipping target and overlay pair " + pkg.mScanPath + " and " +
- opkg.mScanPath + ": overlay not trusted");
+ Slog.w(TAG, "Skipping target and overlay pair " + pkg.codePath + " and " +
+ opkg.codePath + ": overlay not trusted");
return false;
}
HashMap<String, PackageParser.Package> overlaySet = mOverlays.get(pkg.packageName);
if (overlaySet == null) {
- Slog.e(TAG, "was about to create idmap for " + pkg.mScanPath + " and " +
- opkg.mScanPath + " but target package has no known overlays");
+ Slog.e(TAG, "was about to create idmap for " + pkg.codePath + " and " +
+ opkg.codePath + " but target package has no known overlays");
return false;
}
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- if (mInstaller.idmap(pkg.mScanPath, opkg.mScanPath, sharedGid) != 0) {
- Slog.e(TAG, "Failed to generate idmap for " + pkg.mScanPath + " and " + opkg.mScanPath);
+ if (mInstaller.idmap(pkg.codePath, opkg.codePath, sharedGid) != 0) {
+ Slog.e(TAG, "Failed to generate idmap for " + pkg.codePath + " and " + opkg.codePath);
return false;
}
PackageParser.Package[] overlayArray =
@@ -4204,8 +4177,10 @@
Log.i(TAG, srcFile.toString() + " changed; collecting certs");
}
- if (!pp.collectCertificates(pkg, parseFlags)) {
- mLastScanError = pp.getParseError();
+ try {
+ pp.collectCertificates(pkg, parseFlags);
+ } catch (PackageParserException e) {
+ mLastScanError = e.error;
return false;
}
return true;
@@ -4224,11 +4199,13 @@
PackageParser pp = new PackageParser(scanPath);
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
- final PackageParser.Package pkg = pp.parsePackage(scanFile,
- scanPath, mMetrics, parseFlags, (scanMode & SCAN_TRUSTED_OVERLAY) != 0);
- if (pkg == null) {
- mLastScanError = pp.getParseError();
+ final PackageParser.Package pkg;
+ try {
+ pkg = pp.parseMonolithicPackage(scanFile, mMetrics, parseFlags,
+ (scanMode & SCAN_TRUSTED_OVERLAY) != 0);
+ } catch (PackageParserException e) {
+ mLastScanError = e.error;
return null;
}
@@ -4395,12 +4372,13 @@
Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
}
} else {
- resPath = pkg.mScanPath;
+ resPath = pkg.codePath;
}
- codePath = pkg.mScanPath;
+ codePath = pkg.codePath;
// Set application objects path explicitly.
- setApplicationInfoPaths(pkg, codePath, resPath);
+ pkg.applicationInfo.sourceDir = codePath;
+ pkg.applicationInfo.publicSourceDir = resPath;
// Note that we invoke the following method only if we are about to unpack an application
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode
| SCAN_UPDATE_SIGNATURE, currentTime, user, abiOverride);
@@ -4425,13 +4403,6 @@
return scannedPkg;
}
- private static void setApplicationInfoPaths(PackageParser.Package pkg, String destCodePath,
- String destResPath) {
- pkg.mPath = pkg.mScanPath = destCodePath;
- pkg.applicationInfo.sourceDir = destCodePath;
- pkg.applicationInfo.publicSourceDir = destResPath;
- }
-
private static String fixProcessName(String defProcessName,
String processName, int uid) {
if (processName == null) {
@@ -4657,7 +4628,7 @@
boolean performed = false;
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
- String path = pkg.mScanPath;
+ String path = pkg.codePath;
try {
boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
pkg.packageName,
@@ -4830,11 +4801,11 @@
return res;
}
- private int addSharedLibraryLPw(final SharedLibraryEntry file, int num,
+ private void addSharedLibraryLPw(ArraySet<String> usesLibraryFiles, SharedLibraryEntry file,
PackageParser.Package changingLib) {
if (file.path != null) {
- mTmpSharedLibraries[num] = file.path;
- return num+1;
+ usesLibraryFiles.add(file.path);
+ return;
}
PackageParser.Package p = mPackages.get(file.apk);
if (changingLib != null && changingLib.packageName.equals(file.apk)) {
@@ -4847,16 +4818,8 @@
}
}
if (p != null) {
- String path = p.mPath;
- for (int i=0; i<num; i++) {
- if (mTmpSharedLibraries[i].equals(path)) {
- return num;
- }
- }
- mTmpSharedLibraries[num] = p.mPath;
- return num+1;
+ usesLibraryFiles.add(p.codePath);
}
- return num;
}
private boolean updateSharedLibrariesLPw(PackageParser.Package pkg,
@@ -4870,11 +4833,7 @@
}
if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
- if (mTmpSharedLibraries == null ||
- mTmpSharedLibraries.length < mSharedLibraries.size()) {
- mTmpSharedLibraries = new String[mSharedLibraries.size()];
- }
- int num = 0;
+ final ArraySet<String> usesLibraryFiles = new ArraySet<>();
int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;
for (int i=0; i<N; i++) {
final SharedLibraryEntry file = mSharedLibraries.get(pkg.usesLibraries.get(i));
@@ -4885,7 +4844,7 @@
mLastScanError = PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
return false;
}
- num = addSharedLibraryLPw(file, num, changingLib);
+ addSharedLibraryLPw(usesLibraryFiles, file, changingLib);
}
N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0;
for (int i=0; i<N; i++) {
@@ -4895,13 +4854,12 @@
+ " desires unavailable shared library "
+ pkg.usesOptionalLibraries.get(i) + "; ignoring!");
} else {
- num = addSharedLibraryLPw(file, num, changingLib);
+ addSharedLibraryLPw(usesLibraryFiles, file, changingLib);
}
}
- if (num > 0) {
- pkg.usesLibraryFiles = new String[num];
- System.arraycopy(mTmpSharedLibraries, 0,
- pkg.usesLibraryFiles, 0, num);
+ N = usesLibraryFiles.size();
+ if (N > 0) {
+ pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[N]);
} else {
pkg.usesLibraryFiles = null;
}
@@ -4947,7 +4905,7 @@
private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, long currentTime, UserHandle user, String abiOverride) {
- File scanFile = new File(pkg.mScanPath);
+ final File scanFile = new File(pkg.codePath);
if (scanFile == null || pkg.applicationInfo.sourceDir == null ||
pkg.applicationInfo.publicSourceDir == null) {
// Bail out. The resource and code paths haven't been set.
@@ -4991,6 +4949,7 @@
mResolveActivity.packageName = mAndroidApplication.packageName;
mResolveActivity.processName = "system:ui";
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+ mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
mResolveActivity.theme = R.style.Theme_Holo_Dialog_Alert;
mResolveActivity.exported = true;
@@ -5384,7 +5343,7 @@
pkgSetting.uidError = uidError;
}
- String path = scanFile.getPath();
+ final String path = scanFile.getPath();
/* Note: We don't want to unpack the native binaries for
* system applications, unless they have been updated
* (the binaries are already under /system/lib).
@@ -5515,7 +5474,6 @@
handle.close();
}
}
- pkg.mScanPath = path;
if ((scanMode&SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
// We don't do this here during boot because we can do it all
@@ -5660,7 +5618,7 @@
synchronized (mPackages) {
// We don't expect installation to fail beyond this point,
if ((scanMode&SCAN_MONITOR) != 0) {
- mAppDirs.put(pkg.mPath, pkg);
+ mAppDirs.put(pkg.codePath, pkg);
}
// Add the new setting to mSettings
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
@@ -6281,8 +6239,8 @@
// writer
synchronized (mPackages) {
mPackages.remove(pkg.applicationInfo.packageName);
- if (pkg.mPath != null) {
- mAppDirs.remove(pkg.mPath);
+ if (pkg.codePath != null) {
+ mAppDirs.remove(pkg.codePath);
}
cleanPackageDataStructuresLILPw(pkg, chatty);
}
@@ -9849,7 +9807,7 @@
res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
return;
}
- if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) {
+ if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.codePath)) {
// Don't allow installation over an existing package with the same name.
Slog.w(TAG, "Attempt to re-install " + pkgName
+ " without first uninstalling.");
@@ -9861,15 +9819,12 @@
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
System.currentTimeMillis(), user, abiOverride);
if (newPackage == null) {
- Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
+ Slog.w(TAG, "Package couldn't be installed in " + pkg.codePath);
if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
}
} else {
- updateSettingsLI(newPackage,
- installerPackageName,
- null, null,
- res);
+ updateSettingsLI(newPackage, installerPackageName, null, null, res);
// delete the partially installed application. the data directory will have to be
// restored if it was already existing
if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
@@ -9954,15 +9909,12 @@
newPackage = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_TIME,
System.currentTimeMillis(), user, abiOverride);
if (newPackage == null) {
- Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
+ Slog.w(TAG, "Package couldn't be installed in " + pkg.codePath);
if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
}
} else {
- updateSettingsLI(newPackage,
- installerPackageName,
- allUsers, perUserInstalled,
- res);
+ updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res);
updatedSettings = true;
}
}
@@ -9983,7 +9935,7 @@
// package that we deleted.
if (deletedPkg) {
if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + deletedPackage);
- File restoreFile = new File(deletedPackage.mPath);
+ File restoreFile = new File(deletedPackage.codePath);
// Parse old package
boolean oldOnSd = isExternal(deletedPackage);
int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY |
@@ -10068,7 +10020,7 @@
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0, user, abiOverride);
if (newPackage == null) {
- Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
+ Slog.w(TAG, "Package couldn't be installed in " + pkg.codePath);
if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
}
@@ -10114,10 +10066,10 @@
}
// Utility method used to move dex files during install.
- private int moveDexFilesLI(PackageParser.Package newPackage) {
+ private int moveDexFilesLI(String oldCodePath, PackageParser.Package newPackage) {
if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
final String instructionSet = getAppInstructionSet(newPackage.applicationInfo);
- int retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath,
+ int retCode = mInstaller.movedex(oldCodePath, newPackage.codePath,
instructionSet);
if (retCode != 0) {
/*
@@ -10129,8 +10081,8 @@
* file from a previous version of the package.
*/
newPackage.mDexOptNeeded = true;
- mInstaller.rmdex(newPackage.mScanPath, instructionSet);
- mInstaller.rmdex(newPackage.mPath, instructionSet);
+ mInstaller.rmdex(oldCodePath, instructionSet);
+ mInstaller.rmdex(newPackage.codePath, instructionSet);
}
}
return PackageManager.INSTALL_SUCCEEDED;
@@ -10148,13 +10100,7 @@
mSettings.writeLPr();
}
- if ((res.returnCode = moveDexFilesLI(newPackage))
- != PackageManager.INSTALL_SUCCEEDED) {
- // Discontinue if moving dex files failed.
- return;
- }
-
- if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.mPath);
+ if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.codePath);
synchronized (mPackages) {
updatePermissionsLPw(newPackage.packageName, newPackage,
@@ -10221,12 +10167,16 @@
| (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
PackageParser pp = new PackageParser(tmpPackageFile.getPath());
pp.setSeparateProcesses(mSeparateProcesses);
- final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
- null, mMetrics, parseFlags);
- if (pkg == null) {
- res.returnCode = pp.getParseError();
+
+ final PackageParser.Package pkg;
+ try {
+ pkg = pp.parseMonolithicPackage(tmpPackageFile, mMetrics,
+ parseFlags);
+ } catch (PackageParserException e) {
+ res.returnCode = e.error;
return;
}
+
String pkgName = res.name = pkg.packageName;
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
@@ -10234,8 +10184,11 @@
return;
}
}
- if (!pp.collectCertificates(pkg, parseFlags)) {
- res.returnCode = pp.getParseError();
+
+ try {
+ pp.collectCertificates(pkg, parseFlags);
+ } catch (PackageParserException e) {
+ res.returnCode = e.error;
return;
}
@@ -10265,7 +10218,7 @@
synchronized (mPackages) {
// Check whether the newly-scanned package wants to define an already-defined perm
int N = pkg.permissions.size();
- for (int i = 0; i < N; i++) {
+ for (int i = N-1; i >= 0; i--) {
PackageParser.Permission perm = pkg.permissions.get(i);
BasePermission bp = mSettings.mPermissions.get(perm.info.name);
if (bp != null) {
@@ -10273,13 +10226,23 @@
// also includes the "updating the same package" case, of course.
if (compareSignatures(bp.packageSetting.signatures.mSignatures,
pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
- Slog.w(TAG, "Package " + pkg.packageName
- + " attempting to redeclare permission " + perm.info.name
- + " already owned by " + bp.sourcePackage);
- res.returnCode = PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
- res.origPermission = perm.info.name;
- res.origPackage = bp.sourcePackage;
- return;
+ // If the owning package is the system itself, we log but allow
+ // install to proceed; we fail the install on all other permission
+ // redefinitions.
+ if (!bp.sourcePackage.equals("android")) {
+ Slog.w(TAG, "Package " + pkg.packageName
+ + " attempting to redeclare permission " + perm.info.name
+ + " already owned by " + bp.sourcePackage);
+ res.returnCode = PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
+ res.origPermission = perm.info.name;
+ res.origPackage = bp.sourcePackage;
+ return;
+ } else {
+ Slog.w(TAG, "Package " + pkg.packageName
+ + " attempting to redeclare system permission "
+ + perm.info.name + "; ignoring new declaration");
+ pkg.permissions.remove(i);
+ }
}
}
}
@@ -10330,7 +10293,9 @@
return;
}
// Set application objects path explicitly after the rename
- setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
+ pkg.codePath = args.getCodePath();
+ pkg.applicationInfo.sourceDir = args.getCodePath();
+ pkg.applicationInfo.publicSourceDir = args.getResourcePath();
pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
if (replace) {
replacePackageLI(pkg, parseFlags, scanMode, args.user,
@@ -11210,7 +11175,7 @@
publicSrcDir = applicationInfo.publicSourceDir;
}
}
- int res = mInstaller.getSizeInfo(packageName, userHandle, p.mPath, libDirPath,
+ int res = mInstaller.getSizeInfo(packageName, userHandle, p.codePath, libDirPath,
publicSrcDir, asecPath, getAppInstructionSetFromSettings(ps),
pStats);
if (res < 0) {
@@ -12843,7 +12808,7 @@
+ " Aborting move and returning error");
returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
} else {
- final String oldCodePath = pkg.mPath;
+ final String oldCodePath = pkg.codePath;
final String newCodePath = mp.targetArgs.getCodePath();
final String newResPath = mp.targetArgs.getResourcePath();
final String newNativePath = mp.targetArgs
@@ -12873,18 +12838,17 @@
}
if (returnCode == PackageManager.MOVE_SUCCEEDED) {
- pkg.mPath = newCodePath;
+ pkg.codePath = newCodePath;
// Move dex files around
- if (moveDexFilesLI(pkg) != PackageManager.INSTALL_SUCCEEDED) {
+ if (moveDexFilesLI(oldCodePath, pkg) != PackageManager.INSTALL_SUCCEEDED) {
// Moving of dex files failed. Set
// error code and abort move.
- pkg.mPath = pkg.mScanPath;
+ pkg.codePath = oldCodePath;
returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
}
}
if (returnCode == PackageManager.MOVE_SUCCEEDED) {
- pkg.mScanPath = newCodePath;
pkg.applicationInfo.sourceDir = newCodePath;
pkg.applicationInfo.publicSourceDir = newResPath;
pkg.applicationInfo.nativeLibraryDir = newNativePath;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 7162683..b941657 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -161,7 +161,6 @@
private final SparseBooleanArray mRemovingUserIds = new SparseBooleanArray();
private int[] mUserIds;
- private boolean mGuestEnabled;
private int mNextSerialNumber;
private int mUserVersion = 0;
@@ -427,43 +426,6 @@
}
}
- @Override
- public void setGuestEnabled(boolean enable) {
- checkManageUsersPermission("enable guest users");
- synchronized (mPackagesLock) {
- if (mGuestEnabled != enable) {
- mGuestEnabled = enable;
- // Erase any guest user that currently exists
- for (int i = 0; i < mUsers.size(); i++) {
- UserInfo user = mUsers.valueAt(i);
- if (!user.partial && user.isGuest()) {
- if (!enable) {
- removeUser(user.id);
- }
- return;
- }
- }
- // No guest was found
- if (enable) {
- createUser("Guest", UserInfo.FLAG_GUEST);
- }
- }
- }
- }
-
- @Override
- public boolean isGuestEnabled() {
- synchronized (mPackagesLock) {
- return mGuestEnabled;
- }
- }
-
- @Override
- public void wipeUser(int userHandle) {
- checkManageUsersPermission("wipe user");
- // TODO:
- }
-
public void makeInitialized(int userId) {
checkManageUsersPermission("makeInitialized");
synchronized (mPackagesLock) {
@@ -583,7 +545,6 @@
}
private void readUserListLocked() {
- mGuestEnabled = false;
if (!mUserListFile.exists()) {
fallbackToSingleUserLocked();
return;
@@ -625,9 +586,6 @@
if (user != null) {
mUsers.put(user.id, user);
- if (user.isGuest()) {
- mGuestEnabled = true;
- }
if (mNextSerialNumber < 0 || mNextSerialNumber <= user.id) {
mNextSerialNumber = user.id + 1;
}
@@ -1146,7 +1104,7 @@
final UserInfo user;
synchronized (mPackagesLock) {
user = mUsers.get(userHandle);
- if (userHandle == 0 || user == null) {
+ if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {
return false;
}
mRemovingUserIds.put(userHandle, true);
@@ -1273,7 +1231,8 @@
private void sendProfileRemovedBroadcast(int parentUserId, int removedUserId) {
Intent managedProfileIntent = new Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED);
- managedProfileIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ managedProfileIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY |
+ Intent.FLAG_RECEIVER_FOREGROUND);
managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(removedUserId));
mContext.sendBroadcastAsUser(managedProfileIntent, new UserHandle(parentUserId), null);
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index d8671d9..fb4b8f0 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -409,6 +409,9 @@
// Current state of the low power mode setting.
private boolean mLowPowerModeSetting;
+ // Current state of whether the settings are allowing auto low power mode.
+ private boolean mAutoLowPowerModeEnabled;
+
// True if the battery level is currently considered low.
private boolean mBatteryLevelLow;
@@ -558,6 +561,9 @@
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.LOW_POWER_MODE),
false, mSettingsObserver, UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
+ false, mSettingsObserver, UserHandle.USER_ALL);
// Go.
readConfigurationLocked();
updateSettingsLocked();
@@ -645,8 +651,12 @@
final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE, 0) != 0;
- if (lowPowerModeEnabled != mLowPowerModeSetting) {
+ final boolean autoLowPowerModeEnabled = Settings.Global.getInt(resolver,
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 15) != 0;
+ if (lowPowerModeEnabled != mLowPowerModeSetting
+ || autoLowPowerModeEnabled != mAutoLowPowerModeEnabled) {
mLowPowerModeSetting = lowPowerModeEnabled;
+ mAutoLowPowerModeEnabled = autoLowPowerModeEnabled;
updateLowPowerModeLocked();
}
@@ -654,7 +664,8 @@
}
void updateLowPowerModeLocked() {
- final boolean lowPowerModeEnabled = mLowPowerModeSetting || mBatteryLevelLow;
+ final boolean lowPowerModeEnabled = !mIsPowered
+ && (mLowPowerModeSetting || (mAutoLowPowerModeEnabled && mBatteryLevelLow));
if (mLowPowerModeEnabled != lowPowerModeEnabled) {
mLowPowerModeEnabled = lowPowerModeEnabled;
powerHintInternal(POWER_HINT_LOW_POWER_MODE, lowPowerModeEnabled ? 1 : 0);
@@ -1197,7 +1208,7 @@
}
}
- if (oldLevelLow != mBatteryLevelLow) {
+ if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) {
updateLowPowerModeLocked();
}
}
@@ -2168,6 +2179,8 @@
pw.println(" mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
pw.println(" mSandmanScheduled=" + mSandmanScheduled);
pw.println(" mSandmanSummoned=" + mSandmanSummoned);
+ pw.println(" mLowPowerModeEnabled=" + mLowPowerModeEnabled);
+ pw.println(" mBatteryLevelLow=" + mBatteryLevelLow);
pw.println(" mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
pw.println(" mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
pw.println(" mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
@@ -2204,6 +2217,8 @@
pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting);
pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
+ pw.println(" mLowPowerModeSetting=" + mLowPowerModeSetting);
+ pw.println(" mAutoLowPowerModeEnabled=" + mAutoLowPowerModeEnabled);
pw.println(" mMinimumScreenOffTimeoutConfig=" + mMinimumScreenOffTimeoutConfig);
pw.println(" mMaximumScreenDimDurationConfig=" + mMaximumScreenDimDurationConfig);
pw.println(" mMaximumScreenDimRatioConfig=" + mMaximumScreenDimRatioConfig);
diff --git a/services/core/java/com/android/server/task/StateChangedListener.java b/services/core/java/com/android/server/task/StateChangedListener.java
deleted file mode 100644
index b1a4636..0000000
--- a/services/core/java/com/android/server/task/StateChangedListener.java
+++ /dev/null
@@ -1,39 +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.server.task;
-
-import com.android.server.task.controllers.TaskStatus;
-
-/**
- * Interface through which a {@link com.android.server.task.controllers.StateController} informs
- * the {@link com.android.server.task.TaskManagerService} that there are some tasks potentially
- * ready to be run.
- */
-public interface StateChangedListener {
- /**
- * Called by the controller to notify the TaskManager that it should check on the state of a
- * task.
- */
- public void onControllerStateChanged();
-
- /**
- * Called by the controller to notify the TaskManager that regardless of the state of the task,
- * it must be run immediately.
- * @param taskStatus The state of the task which is to be run immediately.
- */
- public void onTaskDeadlineExpired(TaskStatus taskStatus);
-}
diff --git a/services/core/java/com/android/server/task/TaskManagerService.java b/services/core/java/com/android/server/task/TaskManagerService.java
deleted file mode 100644
index a5f865f..0000000
--- a/services/core/java/com/android/server/task/TaskManagerService.java
+++ /dev/null
@@ -1,655 +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.server.task;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import android.app.task.ITaskManager;
-import android.app.task.Task;
-import android.app.task.TaskManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.server.task.controllers.BatteryController;
-import com.android.server.task.controllers.ConnectivityController;
-import com.android.server.task.controllers.IdleController;
-import com.android.server.task.controllers.StateController;
-import com.android.server.task.controllers.TaskStatus;
-import com.android.server.task.controllers.TimeController;
-
-import java.util.LinkedList;
-
-/**
- * Responsible for taking tasks representing work to be performed by a client app, and determining
- * based on the criteria specified when that task should be run against the client application's
- * endpoint.
- * Implements logic for scheduling, and rescheduling tasks. The TaskManagerService knows nothing
- * about constraints, or the state of active tasks. It receives callbacks from the various
- * controllers and completed tasks and operates accordingly.
- *
- * Note on locking: Any operations that manipulate {@link #mTasks} need to lock on that object, and
- * similarly for {@link #mActiveServices}. If both locks need to be held take mTasksSet first and then
- * mActiveService afterwards.
- * @hide
- */
-public class TaskManagerService extends com.android.server.SystemService
- implements StateChangedListener, TaskCompletedListener, TaskMapReadFinishedListener {
- // TODO: Switch this off for final version.
- static final boolean DEBUG = true;
- /** The number of concurrent tasks we run at one time. */
- private static final int MAX_TASK_CONTEXTS_COUNT = 3;
- static final String TAG = "TaskManager";
- /**
- * When a task fails, it gets rescheduled according to its backoff policy. To be nice, we allow
- * this amount of time from the rescheduled time by which the retry must occur.
- */
- private static final long RESCHEDULE_WINDOW_SLOP_MILLIS = 5000L;
-
- /** Master list of tasks. */
- private final TaskStore mTasks;
-
- static final int MSG_TASK_EXPIRED = 0;
- static final int MSG_CHECK_TASKS = 1;
-
- // Policy constants
- /**
- * Minimum # of idle tasks that must be ready in order to force the TM to schedule things
- * early.
- */
- private static final int MIN_IDLE_COUNT = 1;
- /**
- * Minimum # of connectivity tasks that must be ready in order to force the TM to schedule
- * things early.
- */
- private static final int MIN_CONNECTIVITY_COUNT = 2;
- /**
- * Minimum # of tasks (with no particular constraints) for which the TM will be happy running
- * some work early.
- */
- private static final int MIN_READY_TASKS_COUNT = 4;
-
- /**
- * Track Services that have currently active or pending tasks. The index is provided by
- * {@link TaskStatus#getServiceToken()}
- */
- private final List<TaskServiceContext> mActiveServices = new LinkedList<TaskServiceContext>();
- /** List of controllers that will notify this service of updates to tasks. */
- private List<StateController> mControllers;
- /**
- * Queue of pending tasks. The TaskServiceContext class will receive tasks from this list
- * when ready to execute them.
- */
- private final LinkedList<TaskStatus> mPendingTasks = new LinkedList<TaskStatus>();
-
- private final TaskHandler mHandler;
- private final TaskManagerStub mTaskManagerStub;
-
- /**
- * Entry point from client to schedule the provided task.
- * This will add the task to the
- * @param task Task object containing execution parameters
- * @param uId The package identifier of the application this task is for.
- * @param canPersistTask Whether or not the client has the appropriate permissions for persisting
- * of this task.
- * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes.
- */
- public int schedule(Task task, int uId, boolean canPersistTask) {
- TaskStatus taskStatus = new TaskStatus(task, uId, canPersistTask);
- startTrackingTask(taskStatus);
- return TaskManager.RESULT_SUCCESS;
- }
-
- public List<Task> getPendingTasks(int uid) {
- ArrayList<Task> outList = new ArrayList<Task>();
- synchronized (mTasks) {
- for (TaskStatus ts : mTasks.getTasks()) {
- if (ts.getUid() == uid) {
- outList.add(ts.getTask());
- }
- }
- }
- return outList;
- }
-
- /**
- * Entry point from client to cancel all tasks originating from their uid.
- * This will remove the task from the master list, and cancel the task if it was staged for
- * execution or being executed.
- * @param uid To check against for removal of a task.
- */
- public void cancelTaskForUid(int uid) {
- // Remove from master list.
- synchronized (mTasks) {
- if (!mTasks.removeAllByUid(uid)) {
- // If it's not in the master list, it's nowhere.
- return;
- }
- }
- // Remove from pending queue.
- synchronized (mPendingTasks) {
- Iterator<TaskStatus> it = mPendingTasks.iterator();
- while (it.hasNext()) {
- TaskStatus ts = it.next();
- if (ts.getUid() == uid) {
- it.remove();
- }
- }
- }
- // Cancel if running.
- synchronized (mActiveServices) {
- for (TaskServiceContext tsc : mActiveServices) {
- if (tsc.getRunningTask().getUid() == uid) {
- tsc.cancelExecutingTask();
- }
- }
- }
- }
-
- /**
- * Entry point from client to cancel the task corresponding to the taskId provided.
- * This will remove the task from the master list, and cancel the task if it was staged for
- * execution or being executed.
- * @param uid Uid of the calling client.
- * @param taskId Id of the task, provided at schedule-time.
- */
- public void cancelTask(int uid, int taskId) {
- synchronized (mTasks) {
- if (!mTasks.remove(uid, taskId)) {
- // If it's not in the master list, it's nowhere.
- return;
- }
- }
- synchronized (mPendingTasks) {
- Iterator<TaskStatus> it = mPendingTasks.iterator();
- while (it.hasNext()) {
- TaskStatus ts = it.next();
- if (ts.getUid() == uid && ts.getTaskId() == taskId) {
- it.remove();
- // If we got it from pending, it didn't make it to active so return.
- return;
- }
- }
- }
- synchronized (mActiveServices) {
- for (TaskServiceContext tsc : mActiveServices) {
- if (tsc.getRunningTask().getUid() == uid &&
- tsc.getRunningTask().getTaskId() == taskId) {
- tsc.cancelExecutingTask();
- return;
- }
- }
- }
- }
-
- /**
- * Initializes the system service.
- * <p>
- * Subclasses must define a single argument constructor that accepts the context
- * and passes it to super.
- * </p>
- *
- * @param context The system server context.
- */
- public TaskManagerService(Context context) {
- super(context);
- mTasks = TaskStore.initAndGet(this);
- mHandler = new TaskHandler(context.getMainLooper());
- mTaskManagerStub = new TaskManagerStub();
- // Create the "runners".
- for (int i = 0; i < MAX_TASK_CONTEXTS_COUNT; i++) {
- mActiveServices.add(
- new TaskServiceContext(this, context.getMainLooper()));
- }
- // Create the controllers.
- mControllers = new LinkedList<StateController>();
- mControllers.add(ConnectivityController.get(this));
- mControllers.add(TimeController.get(this));
- mControllers.add(IdleController.get(this));
- mControllers.add(BatteryController.get(this));
- }
-
- @Override
- public void onStart() {
- publishBinderService(Context.TASK_SERVICE, mTaskManagerStub);
- }
-
- /**
- * Called when we have a task status object that we need to insert in our
- * {@link com.android.server.task.TaskStore}, and make sure all the relevant controllers know
- * about.
- */
- private void startTrackingTask(TaskStatus taskStatus) {
- synchronized (mTasks) {
- mTasks.add(taskStatus);
- }
- for (StateController controller : mControllers) {
- controller.maybeStartTrackingTask(taskStatus);
-
- }
- }
-
- /**
- * Called when we want to remove a TaskStatus object that we've finished executing. Returns the
- * object removed.
- */
- private boolean stopTrackingTask(TaskStatus taskStatus) {
- boolean removed;
- synchronized (mTasks) {
- // Remove from store as well as controllers.
- removed = mTasks.remove(taskStatus);
- }
- if (removed) {
- for (StateController controller : mControllers) {
- controller.maybeStopTrackingTask(taskStatus);
- }
- }
- return removed;
- }
-
- private boolean cancelTaskOnServiceContext(TaskStatus ts) {
- synchronized (mActiveServices) {
- for (TaskServiceContext tsc : mActiveServices) {
- if (tsc.getRunningTask() == ts) {
- tsc.cancelExecutingTask();
- return true;
- }
- }
- return false;
- }
- }
-
- /**
- * @param ts TaskStatus we are querying against.
- * @return Whether or not the task represented by the status object is currently being run or
- * is pending.
- */
- private boolean isCurrentlyActive(TaskStatus ts) {
- synchronized (mActiveServices) {
- for (TaskServiceContext serviceContext : mActiveServices) {
- if (serviceContext.getRunningTask() == ts) {
- return true;
- }
- }
- return false;
- }
- }
-
- /**
- * A task is rescheduled with exponential back-off if the client requests this from their
- * execution logic.
- * A caveat is for idle-mode tasks, for which the idle-mode constraint will usurp the
- * timeliness of the reschedule. For an idle-mode task, no deadline is given.
- * @param failureToReschedule Provided task status that we will reschedule.
- * @return A newly instantiated TaskStatus with the same constraints as the last task except
- * with adjusted timing constraints.
- */
- private TaskStatus getRescheduleTaskForFailure(TaskStatus failureToReschedule) {
- final long elapsedNowMillis = SystemClock.elapsedRealtime();
- final Task task = failureToReschedule.getTask();
-
- final long initialBackoffMillis = task.getInitialBackoffMillis();
- final int backoffAttempt = failureToReschedule.getNumFailures() + 1;
- long newEarliestRuntimeElapsed = elapsedNowMillis;
-
- switch (task.getBackoffPolicy()) {
- case Task.BackoffPolicy.LINEAR:
- newEarliestRuntimeElapsed += initialBackoffMillis * backoffAttempt;
- break;
- default:
- if (DEBUG) {
- Slog.v(TAG, "Unrecognised back-off policy, defaulting to exponential.");
- }
- case Task.BackoffPolicy.EXPONENTIAL:
- newEarliestRuntimeElapsed += Math.pow(initialBackoffMillis, backoffAttempt);
- break;
- }
- long newLatestRuntimeElapsed = failureToReschedule.hasIdleConstraint() ? Long.MAX_VALUE
- : newEarliestRuntimeElapsed + RESCHEDULE_WINDOW_SLOP_MILLIS;
- return new TaskStatus(failureToReschedule, newEarliestRuntimeElapsed,
- newLatestRuntimeElapsed, backoffAttempt);
- }
-
- /**
- * Called after a periodic has executed so we can to re-add it. We take the last execution time
- * of the task to be the time of completion (i.e. the time at which this function is called).
- * This could be inaccurate b/c the task can run for as long as
- * {@link com.android.server.task.TaskServiceContext#EXECUTING_TIMESLICE_MILLIS}, but will lead
- * to underscheduling at least, rather than if we had taken the last execution time to be the
- * start of the execution.
- * @return A new task representing the execution criteria for this instantiation of the
- * recurring task.
- */
- private TaskStatus getRescheduleTaskForPeriodic(TaskStatus periodicToReschedule) {
- final long elapsedNow = SystemClock.elapsedRealtime();
- // Compute how much of the period is remaining.
- long runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0);
- long newEarliestRunTimeElapsed = elapsedNow + runEarly;
- long period = periodicToReschedule.getTask().getIntervalMillis();
- long newLatestRuntimeElapsed = newEarliestRunTimeElapsed + period;
-
- if (DEBUG) {
- Slog.v(TAG, "Rescheduling executed periodic. New execution window [" +
- newEarliestRunTimeElapsed/1000 + ", " + newLatestRuntimeElapsed/1000 + "]s");
- }
- return new TaskStatus(periodicToReschedule, newEarliestRunTimeElapsed,
- newLatestRuntimeElapsed, 0 /* backoffAttempt */);
- }
-
- // TaskCompletedListener implementations.
-
- /**
- * A task just finished executing. We fetch the
- * {@link com.android.server.task.controllers.TaskStatus} from the store and depending on
- * whether we want to reschedule we readd it to the controllers.
- * @param taskStatus Completed task.
- * @param needsReschedule Whether the implementing class should reschedule this task.
- */
- @Override
- public void onTaskCompleted(TaskStatus taskStatus, boolean needsReschedule) {
- if (!stopTrackingTask(taskStatus)) {
- if (DEBUG) {
- Slog.e(TAG, "Error removing task: could not find task to remove. Was task" +
- "removed while executing?");
- }
- return;
- }
- if (needsReschedule) {
- TaskStatus rescheduled = getRescheduleTaskForFailure(taskStatus);
- startTrackingTask(rescheduled);
- } else if (taskStatus.getTask().isPeriodic()) {
- TaskStatus rescheduledPeriodic = getRescheduleTaskForPeriodic(taskStatus);
- startTrackingTask(rescheduledPeriodic);
- }
- mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
- }
-
- // StateChangedListener implementations.
-
- /**
- * Off-board work to our handler thread as quickly as possible, b/c this call is probably being
- * made on the main thread.
- * For now this takes the task and if it's ready to run it will run it. In future we might not
- * provide the task, so that the StateChangedListener has to run through its list of tasks to
- * see which are ready. This will further decouple the controllers from the execution logic.
- */
- @Override
- public void onControllerStateChanged() {
- // Post a message to to run through the list of tasks and start/stop any that are eligible.
- mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
- }
-
- @Override
- public void onTaskDeadlineExpired(TaskStatus taskStatus) {
- mHandler.obtainMessage(MSG_TASK_EXPIRED, taskStatus);
- }
-
- /**
- * Disk I/O is finished, take the list of tasks we read from disk and add them to our
- * {@link TaskStore}.
- * This is run on the {@link com.android.server.IoThread} instance, which is a separate thread,
- * and is called once at boot.
- */
- @Override
- public void onTaskMapReadFinished(List<TaskStatus> tasks) {
- synchronized (mTasks) {
- for (TaskStatus ts : tasks) {
- if (mTasks.contains(ts)) {
- // An app with BOOT_COMPLETED *might* have decided to reschedule their task, in
- // the same amount of time it took us to read it from disk. If this is the case
- // we leave it be.
- continue;
- }
- startTrackingTask(ts);
- }
- }
- }
-
- private class TaskHandler extends Handler {
-
- public TaskHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message message) {
- switch (message.what) {
- case MSG_TASK_EXPIRED:
- final TaskStatus expired = (TaskStatus) message.obj; // Unused for now.
- queueReadyTasksForExecutionH();
- break;
- case MSG_CHECK_TASKS:
- // Check the list of tasks and run some of them if we feel inclined.
- maybeQueueReadyTasksForExecutionH();
- break;
- }
- maybeRunNextPendingTaskH();
- // Don't remove TASK_EXPIRED in case one came along while processing the queue.
- removeMessages(MSG_CHECK_TASKS);
- }
-
- /**
- * Run through list of tasks and execute all possible - at least one is expired so we do
- * as many as we can.
- */
- private void queueReadyTasksForExecutionH() {
- synchronized (mTasks) {
- for (TaskStatus ts : mTasks.getTasks()) {
- final boolean criteriaSatisfied = ts.isReady();
- final boolean isRunning = isCurrentlyActive(ts);
- if (criteriaSatisfied && !isRunning) {
- synchronized (mPendingTasks) {
- mPendingTasks.add(ts);
- }
- } else if (!criteriaSatisfied && isRunning) {
- cancelTaskOnServiceContext(ts);
- }
- }
- }
- }
-
- /**
- * The state of at least one task has changed. Here is where we could enforce various
- * policies on when we want to execute tasks.
- * Right now the policy is such:
- * If >1 of the ready tasks is idle mode we send all of them off
- * if more than 2 network connectivity tasks are ready we send them all off.
- * If more than 4 tasks total are ready we send them all off.
- * TODO: It would be nice to consolidate these sort of high-level policies somewhere.
- */
- private void maybeQueueReadyTasksForExecutionH() {
- synchronized (mTasks) {
- int idleCount = 0;
- int connectivityCount = 0;
- List<TaskStatus> runnableTasks = new ArrayList<TaskStatus>();
- for (TaskStatus ts : mTasks.getTasks()) {
- final boolean criteriaSatisfied = ts.isReady();
- final boolean isRunning = isCurrentlyActive(ts);
- if (criteriaSatisfied && !isRunning) {
- if (ts.hasIdleConstraint()) {
- idleCount++;
- }
- if (ts.hasConnectivityConstraint() || ts.hasMeteredConstraint()) {
- connectivityCount++;
- }
- runnableTasks.add(ts);
- } else if (!criteriaSatisfied && isRunning) {
- cancelTaskOnServiceContext(ts);
- }
- }
- if (idleCount >= MIN_IDLE_COUNT || connectivityCount >= MIN_CONNECTIVITY_COUNT ||
- runnableTasks.size() >= MIN_READY_TASKS_COUNT) {
- for (TaskStatus ts : runnableTasks) {
- synchronized (mPendingTasks) {
- mPendingTasks.add(ts);
- }
- }
- }
- }
- }
-
- /**
- * Checks the state of the pending queue against any available
- * {@link com.android.server.task.TaskServiceContext} that can run a new task.
- * {@link com.android.server.task.TaskServiceContext}.
- */
- private void maybeRunNextPendingTaskH() {
- TaskStatus nextPending;
- synchronized (mPendingTasks) {
- nextPending = mPendingTasks.poll();
- }
- if (nextPending == null) {
- return;
- }
-
- synchronized (mActiveServices) {
- for (TaskServiceContext tsc : mActiveServices) {
- if (tsc.isAvailable()) {
- if (tsc.executeRunnableTask(nextPending)) {
- return;
- }
- }
- }
- }
- }
- }
-
- /**
- * Binder stub trampoline implementation
- */
- final class TaskManagerStub extends ITaskManager.Stub {
- /** Cache determination of whether a given app can persist tasks
- * key is uid of the calling app; value is undetermined/true/false
- */
- private final SparseArray<Boolean> mPersistCache = new SparseArray<Boolean>();
-
- // Determine whether the caller is allowed to persist tasks, with a small cache
- // because the lookup is expensive enough that we'd like to avoid repeating it.
- // This must be called from within the calling app's binder identity!
- private boolean canCallerPersistTasks() {
- final boolean canPersist;
- final int callingUid = Binder.getCallingUid();
- synchronized (mPersistCache) {
- Boolean cached = mPersistCache.get(callingUid);
- if (cached) {
- canPersist = cached.booleanValue();
- } else {
- // Persisting tasks is tantamount to running at boot, so we permit
- // it when the app has declared that it uses the RECEIVE_BOOT_COMPLETED
- // permission
- int result = getContext().checkCallingPermission(
- android.Manifest.permission.RECEIVE_BOOT_COMPLETED);
- canPersist = (result == PackageManager.PERMISSION_GRANTED);
- mPersistCache.put(callingUid, canPersist);
- }
- }
- return canPersist;
- }
-
- // ITaskManager implementation
- @Override
- public int schedule(Task task) throws RemoteException {
- final boolean canPersist = canCallerPersistTasks();
- final int uid = Binder.getCallingUid();
-
- long ident = Binder.clearCallingIdentity();
- try {
- return TaskManagerService.this.schedule(task, uid, canPersist);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public List<Task> getAllPendingTasks() throws RemoteException {
- final int uid = Binder.getCallingUid();
-
- long ident = Binder.clearCallingIdentity();
- try {
- return TaskManagerService.this.getPendingTasks(uid);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public void cancelAll() throws RemoteException {
- final int uid = Binder.getCallingUid();
-
- long ident = Binder.clearCallingIdentity();
- try {
- TaskManagerService.this.cancelTaskForUid(uid);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public void cancel(int taskId) throws RemoteException {
- final int uid = Binder.getCallingUid();
-
- long ident = Binder.clearCallingIdentity();
- try {
- TaskManagerService.this.cancelTask(uid, taskId);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- /**
- * "dumpsys" infrastructure
- */
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-
- long identityToken = Binder.clearCallingIdentity();
- try {
- TaskManagerService.this.dumpInternal(pw);
- } finally {
- Binder.restoreCallingIdentity(identityToken);
- }
- }
- };
-
- void dumpInternal(PrintWriter pw) {
- synchronized (mTasks) {
- pw.print("Registered tasks:");
- if (mTasks.size() > 0) {
- for (TaskStatus ts : mTasks.getTasks()) {
- pw.println();
- ts.dump(pw, " ");
- }
- } else {
- pw.println();
- pw.println("No tasks scheduled.");
- }
- }
- pw.println();
- }
-}
diff --git a/services/core/java/com/android/server/task/TaskStore.java b/services/core/java/com/android/server/task/TaskStore.java
deleted file mode 100644
index 6bb00b1..0000000
--- a/services/core/java/com/android/server/task/TaskStore.java
+++ /dev/null
@@ -1,655 +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.server.task;
-
-import android.content.ComponentName;
-import android.app.task.Task;
-import android.content.Context;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.PersistableBundle;
-import android.os.SystemClock;
-import android.util.AtomicFile;
-import android.util.ArraySet;
-import android.util.Pair;
-import android.util.Slog;
-import android.util.Xml;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.server.IoThread;
-import com.android.server.task.controllers.TaskStatus;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-/**
- * Maintain a list of classes, and accessor methods/logic for these tasks.
- * This class offers the following functionality:
- * - When a task is added, it will determine if the task requirements have changed (update) and
- * whether the controllers need to be updated.
- * - Persists Tasks, figures out when to to rewrite the Task to disk.
- * - Is threadsafe.
- * - Handles rescheduling of tasks.
- * - When a periodic task is executed and must be re-added.
- * - When a task fails and the client requests that it be retried with backoff.
- * - This class <strong>is not</strong> thread-safe.
- *
- * Note on locking:
- * All callers to this class must <strong>lock on the class object they are calling</strong>.
- * This is important b/c {@link com.android.server.task.TaskStore.WriteTasksMapToDiskRunnable}
- * and {@link com.android.server.task.TaskStore.ReadTaskMapFromDiskRunnable} lock on that
- * object.
- */
-public class TaskStore {
- private static final String TAG = "TaskManagerStore";
- private static final boolean DEBUG = TaskManagerService.DEBUG;
-
- /** Threshold to adjust how often we want to write to the db. */
- private static final int MAX_OPS_BEFORE_WRITE = 1;
- final ArraySet<TaskStatus> mTasksSet;
- final Context mContext;
-
- private int mDirtyOperations;
-
- private static final Object sSingletonLock = new Object();
- private final AtomicFile mTasksFile;
- /** Handler backed by IoThread for writing to disk. */
- private final Handler mIoHandler = IoThread.getHandler();
- private static TaskStore sSingleton;
-
- /** Used by the {@Link TaskManagerService} to instantiate the TaskStore. */
- static TaskStore initAndGet(TaskManagerService taskManagerService) {
- synchronized (sSingletonLock) {
- if (sSingleton == null) {
- sSingleton = new TaskStore(taskManagerService.getContext(),
- Environment.getDataDirectory(), taskManagerService);
- }
- return sSingleton;
- }
- }
-
- @VisibleForTesting
- public static TaskStore initAndGetForTesting(Context context, File dataDir,
- TaskMapReadFinishedListener callback) {
- return new TaskStore(context, dataDir, callback);
- }
-
- private TaskStore(Context context, File dataDir, TaskMapReadFinishedListener callback) {
- mContext = context;
- mDirtyOperations = 0;
-
- File systemDir = new File(dataDir, "system");
- File taskDir = new File(systemDir, "task");
- taskDir.mkdirs();
- mTasksFile = new AtomicFile(new File(taskDir, "tasks.xml"));
-
- mTasksSet = new ArraySet<TaskStatus>();
-
- readTaskMapFromDiskAsync(callback);
- }
-
- /**
- * Add a task to the master list, persisting it if necessary. If the TaskStatus already exists,
- * it will be replaced.
- * @param taskStatus Task to add.
- * @return Whether or not an equivalent TaskStatus was replaced by this operation.
- */
- public boolean add(TaskStatus taskStatus) {
- boolean replaced = mTasksSet.remove(taskStatus);
- mTasksSet.add(taskStatus);
- if (taskStatus.isPersisted()) {
- maybeWriteStatusToDiskAsync();
- }
- return replaced;
- }
-
- /**
- * Whether this taskStatus object already exists in the TaskStore.
- */
- public boolean contains(TaskStatus taskStatus) {
- return mTasksSet.contains(taskStatus);
- }
-
- public int size() {
- return mTasksSet.size();
- }
-
- /**
- * Remove the provided task. Will also delete the task if it was persisted.
- * @return Whether or not the task existed to be removed.
- */
- public boolean remove(TaskStatus taskStatus) {
- boolean removed = mTasksSet.remove(taskStatus);
- if (!removed) {
- if (DEBUG) {
- Slog.d(TAG, "Couldn't remove task: didn't exist: " + taskStatus);
- }
- return false;
- }
- maybeWriteStatusToDiskAsync();
- return removed;
- }
-
- @VisibleForTesting
- public void clear() {
- mTasksSet.clear();
- maybeWriteStatusToDiskAsync();
- }
-
- /**
- * Removes all TaskStatus objects for a given uid from the master list. Note that it is
- * possible to remove a task that is pending/active. This operation will succeed, and the
- * removal will take effect when the task has completed executing.
- * @param uid Uid of the requesting app.
- * @return True if at least one task was removed, false if nothing matching the provided uId
- * was found.
- */
- public boolean removeAllByUid(int uid) {
- Iterator<TaskStatus> it = mTasksSet.iterator();
- while (it.hasNext()) {
- TaskStatus ts = it.next();
- if (ts.getUid() == uid) {
- it.remove();
- maybeWriteStatusToDiskAsync();
- return true;
- }
- }
- return false;
- }
-
- /**
- * Remove the TaskStatus that matches the provided uId and taskId. Note that it is possible
- * to remove a task that is pending/active. This operation will succeed, and the removal will
- * take effect when the task has completed executing.
- * @param uid Uid of the requesting app.
- * @param taskId Task id, specified at schedule-time.
- * @return true if a removal occurred, false if the provided parameters didn't match anything.
- */
- public boolean remove(int uid, int taskId) {
- boolean changed = false;
- Iterator<TaskStatus> it = mTasksSet.iterator();
- while (it.hasNext()) {
- TaskStatus ts = it.next();
- if (ts.getUid() == uid && ts.getTaskId() == taskId) {
- it.remove();
- changed = true;
- }
- }
- if (changed) {
- maybeWriteStatusToDiskAsync();
- }
- return changed;
- }
-
- /**
- * @return The live array of TaskStatus objects.
- */
- public ArraySet<TaskStatus> getTasks() {
- return mTasksSet;
- }
-
- /** Version of the db schema. */
- private static final int TASKS_FILE_VERSION = 0;
- /** Tag corresponds to constraints this task needs. */
- private static final String XML_TAG_PARAMS_CONSTRAINTS = "constraints";
- /** Tag corresponds to execution parameters. */
- private static final String XML_TAG_PERIODIC = "periodic";
- private static final String XML_TAG_ONEOFF = "one-off";
- private static final String XML_TAG_EXTRAS = "extras";
-
- /**
- * Every time the state changes we write all the tasks in one swathe, instead of trying to
- * track incremental changes.
- * @return Whether the operation was successful. This will only fail for e.g. if the system is
- * low on storage. If this happens, we continue as normal
- */
- private void maybeWriteStatusToDiskAsync() {
- mDirtyOperations++;
- if (mDirtyOperations >= MAX_OPS_BEFORE_WRITE) {
- if (DEBUG) {
- Slog.v(TAG, "Writing tasks to disk.");
- }
- mIoHandler.post(new WriteTasksMapToDiskRunnable());
- }
- }
-
- private void readTaskMapFromDiskAsync(TaskMapReadFinishedListener callback) {
- mIoHandler.post(new ReadTaskMapFromDiskRunnable(callback));
- }
-
- public void readTaskMapFromDisk(TaskMapReadFinishedListener callback) {
- new ReadTaskMapFromDiskRunnable(callback).run();
- }
-
- /**
- * Runnable that writes {@link #mTasksSet} out to xml.
- * NOTE: This Runnable locks on TaskStore.this
- */
- private class WriteTasksMapToDiskRunnable implements Runnable {
- @Override
- public void run() {
- final long startElapsed = SystemClock.elapsedRealtime();
- synchronized (TaskStore.this) {
- writeTasksMapImpl();
- }
- if (TaskManagerService.DEBUG) {
- Slog.v(TAG, "Finished writing, took " + (SystemClock.elapsedRealtime()
- - startElapsed) + "ms");
- }
- }
-
- private void writeTasksMapImpl() {
- try {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(baos, "utf-8");
- out.startDocument(null, true);
- out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
- out.startTag(null, "task-info");
- out.attribute(null, "version", Integer.toString(TASKS_FILE_VERSION));
- for (int i = 0; i < mTasksSet.size(); i++) {
- final TaskStatus taskStatus = mTasksSet.valueAt(i);
- if (DEBUG) {
- Slog.d(TAG, "Saving task " + taskStatus.getTaskId());
- }
- out.startTag(null, "task");
- addIdentifierAttributesToTaskTag(out, taskStatus);
- writeConstraintsToXml(out, taskStatus);
- writeExecutionCriteriaToXml(out, taskStatus);
- writeBundleToXml(taskStatus.getExtras(), out);
- out.endTag(null, "task");
- }
- out.endTag(null, "task-info");
- out.endDocument();
-
- // Write out to disk in one fell sweep.
- FileOutputStream fos = mTasksFile.startWrite();
- fos.write(baos.toByteArray());
- mTasksFile.finishWrite(fos);
- mDirtyOperations = 0;
- } catch (IOException e) {
- if (DEBUG) {
- Slog.v(TAG, "Error writing out task data.", e);
- }
- } catch (XmlPullParserException e) {
- if (DEBUG) {
- Slog.d(TAG, "Error persisting bundle.", e);
- }
- }
- }
-
- /** Write out a tag with data comprising the required fields of this task and its client. */
- private void addIdentifierAttributesToTaskTag(XmlSerializer out, TaskStatus taskStatus)
- throws IOException {
- out.attribute(null, "taskid", Integer.toString(taskStatus.getTaskId()));
- out.attribute(null, "package", taskStatus.getServiceComponent().getPackageName());
- out.attribute(null, "class", taskStatus.getServiceComponent().getClassName());
- out.attribute(null, "uid", Integer.toString(taskStatus.getUid()));
- }
-
- private void writeBundleToXml(PersistableBundle extras, XmlSerializer out)
- throws IOException, XmlPullParserException {
- out.startTag(null, XML_TAG_EXTRAS);
- extras.saveToXml(out);
- out.endTag(null, XML_TAG_EXTRAS);
- }
- /**
- * Write out a tag with data identifying this tasks constraints. If the constraint isn't here
- * it doesn't apply.
- */
- private void writeConstraintsToXml(XmlSerializer out, TaskStatus taskStatus) throws IOException {
- out.startTag(null, XML_TAG_PARAMS_CONSTRAINTS);
- if (taskStatus.hasMeteredConstraint()) {
- out.attribute(null, "unmetered", Boolean.toString(true));
- }
- if (taskStatus.hasConnectivityConstraint()) {
- out.attribute(null, "connectivity", Boolean.toString(true));
- }
- if (taskStatus.hasIdleConstraint()) {
- out.attribute(null, "idle", Boolean.toString(true));
- }
- if (taskStatus.hasChargingConstraint()) {
- out.attribute(null, "charging", Boolean.toString(true));
- }
- out.endTag(null, XML_TAG_PARAMS_CONSTRAINTS);
- }
-
- private void writeExecutionCriteriaToXml(XmlSerializer out, TaskStatus taskStatus)
- throws IOException {
- final Task task = taskStatus.getTask();
- if (taskStatus.getTask().isPeriodic()) {
- out.startTag(null, XML_TAG_PERIODIC);
- out.attribute(null, "period", Long.toString(task.getIntervalMillis()));
- } else {
- out.startTag(null, XML_TAG_ONEOFF);
- }
-
- if (taskStatus.hasDeadlineConstraint()) {
- // Wall clock deadline.
- final long deadlineWallclock = System.currentTimeMillis() +
- (taskStatus.getLatestRunTimeElapsed() - SystemClock.elapsedRealtime());
- out.attribute(null, "deadline", Long.toString(deadlineWallclock));
- }
- if (taskStatus.hasTimingDelayConstraint()) {
- final long delayWallclock = System.currentTimeMillis() +
- (taskStatus.getEarliestRunTime() - SystemClock.elapsedRealtime());
- out.attribute(null, "delay", Long.toString(delayWallclock));
- }
-
- // Only write out back-off policy if it differs from the default.
- // This also helps the case where the task is idle -> these aren't allowed to specify
- // back-off.
- if (taskStatus.getTask().getInitialBackoffMillis() != Task.DEFAULT_INITIAL_BACKOFF_MILLIS
- || taskStatus.getTask().getBackoffPolicy() != Task.DEFAULT_BACKOFF_POLICY) {
- out.attribute(null, "backoff-policy", Integer.toString(task.getBackoffPolicy()));
- out.attribute(null, "initial-backoff", Long.toString(task.getInitialBackoffMillis()));
- }
- if (task.isPeriodic()) {
- out.endTag(null, XML_TAG_PERIODIC);
- } else {
- out.endTag(null, XML_TAG_ONEOFF);
- }
- }
- }
-
- /**
- * Runnable that reads list of persisted task from xml.
- * NOTE: This Runnable locks on TaskStore.this
- */
- private class ReadTaskMapFromDiskRunnable implements Runnable {
- private TaskMapReadFinishedListener mCallback;
- public ReadTaskMapFromDiskRunnable(TaskMapReadFinishedListener callback) {
- mCallback = callback;
- }
-
- @Override
- public void run() {
- try {
- List<TaskStatus> tasks;
- synchronized (TaskStore.this) {
- tasks = readTaskMapImpl();
- }
- if (tasks != null) {
- mCallback.onTaskMapReadFinished(tasks);
- }
- } catch (FileNotFoundException e) {
- if (TaskManagerService.DEBUG) {
- Slog.d(TAG, "Could not find tasks file, probably there was nothing to load.");
- }
- } catch (XmlPullParserException e) {
- if (TaskManagerService.DEBUG) {
- Slog.d(TAG, "Error parsing xml.", e);
- }
- } catch (IOException e) {
- if (TaskManagerService.DEBUG) {
- Slog.d(TAG, "Error parsing xml.", e);
- }
- }
- }
-
- private List<TaskStatus> readTaskMapImpl() throws XmlPullParserException, IOException {
- FileInputStream fis = mTasksFile.openRead();
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(fis, null);
-
- int eventType = parser.getEventType();
- while (eventType != XmlPullParser.START_TAG &&
- eventType != XmlPullParser.END_DOCUMENT) {
- eventType = parser.next();
- Slog.d(TAG, parser.getName());
- }
- if (eventType == XmlPullParser.END_DOCUMENT) {
- if (DEBUG) {
- Slog.d(TAG, "No persisted tasks.");
- }
- return null;
- }
-
- String tagName = parser.getName();
- if ("task-info".equals(tagName)) {
- final List<TaskStatus> tasks = new ArrayList<TaskStatus>();
- // Read in version info.
- try {
- int version = Integer.valueOf(parser.getAttributeValue(null, "version"));
- if (version != TASKS_FILE_VERSION) {
- Slog.d(TAG, "Invalid version number, aborting tasks file read.");
- return null;
- }
- } catch (NumberFormatException e) {
- Slog.e(TAG, "Invalid version number, aborting tasks file read.");
- return null;
- }
- eventType = parser.next();
- do {
- // Read each <task/>
- if (eventType == XmlPullParser.START_TAG) {
- tagName = parser.getName();
- // Start reading task.
- if ("task".equals(tagName)) {
- TaskStatus persistedTask = restoreTaskFromXml(parser);
- if (persistedTask != null) {
- if (DEBUG) {
- Slog.d(TAG, "Read out " + persistedTask);
- }
- tasks.add(persistedTask);
- } else {
- Slog.d(TAG, "Error reading task from file.");
- }
- }
- }
- eventType = parser.next();
- } while (eventType != XmlPullParser.END_DOCUMENT);
- return tasks;
- }
- return null;
- }
-
- /**
- * @param parser Xml parser at the beginning of a "<task/>" tag. The next "parser.next()" call
- * will take the parser into the body of the task tag.
- * @return Newly instantiated task holding all the information we just read out of the xml tag.
- */
- private TaskStatus restoreTaskFromXml(XmlPullParser parser) throws XmlPullParserException,
- IOException {
- Task.Builder taskBuilder;
- int uid;
-
- // Read out task identifier attributes.
- try {
- taskBuilder = buildBuilderFromXml(parser);
- uid = Integer.valueOf(parser.getAttributeValue(null, "uid"));
- } catch (NumberFormatException e) {
- Slog.e(TAG, "Error parsing task's required fields, skipping");
- return null;
- }
-
- int eventType;
- // Read out constraints tag.
- do {
- eventType = parser.next();
- } while (eventType == XmlPullParser.TEXT); // Push through to next START_TAG.
-
- if (!(eventType == XmlPullParser.START_TAG &&
- XML_TAG_PARAMS_CONSTRAINTS.equals(parser.getName()))) {
- // Expecting a <constraints> start tag.
- return null;
- }
- try {
- buildConstraintsFromXml(taskBuilder, parser);
- } catch (NumberFormatException e) {
- Slog.d(TAG, "Error reading constraints, skipping.");
- return null;
- }
- parser.next(); // Consume </constraints>
-
- // Read out execution parameters tag.
- do {
- eventType = parser.next();
- } while (eventType == XmlPullParser.TEXT);
- if (eventType != XmlPullParser.START_TAG) {
- return null;
- }
-
- Pair<Long, Long> runtimes;
- try {
- runtimes = buildExecutionTimesFromXml(parser);
- } catch (NumberFormatException e) {
- if (DEBUG) {
- Slog.d(TAG, "Error parsing execution time parameters, skipping.");
- }
- return null;
- }
-
- if (XML_TAG_PERIODIC.equals(parser.getName())) {
- try {
- String val = parser.getAttributeValue(null, "period");
- taskBuilder.setPeriodic(Long.valueOf(val));
- } catch (NumberFormatException e) {
- Slog.d(TAG, "Error reading periodic execution criteria, skipping.");
- return null;
- }
- } else if (XML_TAG_ONEOFF.equals(parser.getName())) {
- try {
- if (runtimes.first != TaskStatus.DEFAULT_EARLIEST_RUNTIME) {
- taskBuilder.setMinimumLatency(runtimes.first - SystemClock.elapsedRealtime());
- }
- if (runtimes.second != TaskStatus.DEFAULT_LATEST_RUNTIME) {
- taskBuilder.setOverrideDeadline(
- runtimes.second - SystemClock.elapsedRealtime());
- }
- } catch (NumberFormatException e) {
- Slog.d(TAG, "Error reading task execution criteria, skipping.");
- return null;
- }
- } else {
- if (DEBUG) {
- Slog.d(TAG, "Invalid parameter tag, skipping - " + parser.getName());
- }
- // Expecting a parameters start tag.
- return null;
- }
- maybeBuildBackoffPolicyFromXml(taskBuilder, parser);
-
- parser.nextTag(); // Consume parameters end tag.
-
- // Read out extras Bundle.
- do {
- eventType = parser.next();
- } while (eventType == XmlPullParser.TEXT);
- if (!(eventType == XmlPullParser.START_TAG && XML_TAG_EXTRAS.equals(parser.getName()))) {
- if (DEBUG) {
- Slog.d(TAG, "Error reading extras, skipping.");
- }
- return null;
- }
-
- PersistableBundle extras = PersistableBundle.restoreFromXml(parser);
- taskBuilder.setExtras(extras);
- parser.nextTag(); // Consume </extras>
-
- return new TaskStatus(taskBuilder.build(), uid, runtimes.first, runtimes.second);
- }
-
- private Task.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberFormatException {
- // Pull out required fields from <task> attributes.
- int taskId = Integer.valueOf(parser.getAttributeValue(null, "taskid"));
- String packageName = parser.getAttributeValue(null, "package");
- String className = parser.getAttributeValue(null, "class");
- ComponentName cname = new ComponentName(packageName, className);
-
- return new Task.Builder(taskId, cname);
- }
-
- private void buildConstraintsFromXml(Task.Builder taskBuilder, XmlPullParser parser) {
- String val = parser.getAttributeValue(null, "unmetered");
- if (val != null) {
- taskBuilder.setRequiredNetworkCapabilities(Task.NetworkType.UNMETERED);
- }
- val = parser.getAttributeValue(null, "connectivity");
- if (val != null) {
- taskBuilder.setRequiredNetworkCapabilities(Task.NetworkType.ANY);
- }
- val = parser.getAttributeValue(null, "idle");
- if (val != null) {
- taskBuilder.setRequiresDeviceIdle(true);
- }
- val = parser.getAttributeValue(null, "charging");
- if (val != null) {
- taskBuilder.setRequiresCharging(true);
- }
- }
-
- /**
- * Builds the back-off policy out of the params tag. These attributes may not exist, depending
- * on whether the back-off was set when the task was first scheduled.
- */
- private void maybeBuildBackoffPolicyFromXml(Task.Builder taskBuilder, XmlPullParser parser) {
- String val = parser.getAttributeValue(null, "initial-backoff");
- if (val != null) {
- long initialBackoff = Long.valueOf(val);
- val = parser.getAttributeValue(null, "backoff-policy");
- int backoffPolicy = Integer.valueOf(val); // Will throw NFE which we catch higher up.
- taskBuilder.setBackoffCriteria(initialBackoff, backoffPolicy);
- }
- }
-
- /**
- * Convenience function to read out and convert deadline and delay from xml into elapsed real
- * time.
- * @return A {@link android.util.Pair}, where the first value is the earliest elapsed runtime
- * and the second is the latest elapsed runtime.
- */
- private Pair<Long, Long> buildExecutionTimesFromXml(XmlPullParser parser)
- throws NumberFormatException {
- // Pull out execution time data.
- final long nowWallclock = System.currentTimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
-
- long earliestRunTimeElapsed = TaskStatus.DEFAULT_EARLIEST_RUNTIME;
- long latestRunTimeElapsed = TaskStatus.DEFAULT_LATEST_RUNTIME;
- String val = parser.getAttributeValue(null, "deadline");
- if (val != null) {
- long latestRuntimeWallclock = Long.valueOf(val);
- long maxDelayElapsed =
- Math.max(latestRuntimeWallclock - nowWallclock, 0);
- latestRunTimeElapsed = nowElapsed + maxDelayElapsed;
- }
- val = parser.getAttributeValue(null, "delay");
- if (val != null) {
- long earliestRuntimeWallclock = Long.valueOf(val);
- long minDelayElapsed =
- Math.max(earliestRuntimeWallclock - nowWallclock, 0);
- earliestRunTimeElapsed = nowElapsed + minDelayElapsed;
-
- }
- return Pair.create(earliestRunTimeElapsed, latestRunTimeElapsed);
- }
- }
-}
diff --git a/services/core/java/com/android/server/task/controllers/ConnectivityController.java b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
deleted file mode 100644
index 4819460..0000000
--- a/services/core/java/com/android/server/task/controllers/ConnectivityController.java
+++ /dev/null
@@ -1,143 +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.server.task.controllers;
-
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.os.UserHandle;
-import android.util.Log;
-import android.util.Slog;
-
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
-
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Handles changes in connectivity.
- * We are only interested in metered vs. unmetered networks, and we're interested in them on a
- * per-user basis.
- */
-public class ConnectivityController extends StateController {
- private static final String TAG = "TaskManager.Connectivity";
-
- private final List<TaskStatus> mTrackedTasks = new LinkedList<TaskStatus>();
- private final BroadcastReceiver mConnectivityChangedReceiver =
- new ConnectivityChangedReceiver();
- /** Singleton. */
- private static ConnectivityController mSingleton;
-
- /** Track whether the latest active network is metered. */
- private boolean mMetered;
- /** Track whether the latest active network is connected. */
- private boolean mConnectivity;
-
- public static synchronized ConnectivityController get(TaskManagerService taskManager) {
- if (mSingleton == null) {
- mSingleton = new ConnectivityController(taskManager, taskManager.getContext());
- }
- return mSingleton;
- }
-
- private ConnectivityController(StateChangedListener stateChangedListener, Context context) {
- super(stateChangedListener, context);
- // Register connectivity changed BR.
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- mContext.registerReceiverAsUser(
- mConnectivityChangedReceiver, UserHandle.ALL, intentFilter, null, null);
- }
-
- @Override
- public synchronized void maybeStartTrackingTask(TaskStatus taskStatus) {
- if (taskStatus.hasConnectivityConstraint() || taskStatus.hasMeteredConstraint()) {
- taskStatus.connectivityConstraintSatisfied.set(mConnectivity);
- taskStatus.meteredConstraintSatisfied.set(mMetered);
- mTrackedTasks.add(taskStatus);
- }
- }
-
- @Override
- public synchronized void maybeStopTrackingTask(TaskStatus taskStatus) {
- mTrackedTasks.remove(taskStatus);
- }
-
- /**
- * @param userId Id of the user for whom we are updating the connectivity state.
- */
- private void updateTrackedTasks(int userId) {
- boolean changed = false;
- for (TaskStatus ts : mTrackedTasks) {
- if (ts.getUserId() != userId) {
- continue;
- }
- boolean prevIsConnected = ts.connectivityConstraintSatisfied.getAndSet(mConnectivity);
- boolean prevIsMetered = ts.meteredConstraintSatisfied.getAndSet(mMetered);
- if (prevIsConnected != mConnectivity || prevIsMetered != mMetered) {
- changed = true;
- }
- }
- if (changed) {
- mStateChangedListener.onControllerStateChanged();
- }
- }
-
- class ConnectivityChangedReceiver extends BroadcastReceiver {
- /**
- * We'll receive connectivity changes for each user here, which we process independently.
- * We are only interested in the active network here. We're only interested in the active
- * network, b/c the end result of this will be for apps to try to hit the network.
- * @param context The Context in which the receiver is running.
- * @param intent The Intent being received.
- */
- // TODO: Test whether this will be called twice for each user.
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
- final int networkType =
- intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
- ConnectivityManager.TYPE_NONE);
- // Connectivity manager for THIS context - important!
- final ConnectivityManager connManager = (ConnectivityManager)
- context.getSystemService(Context.CONNECTIVITY_SERVICE);
- final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
- // This broadcast gets sent a lot, only update if the active network has changed.
- if (activeNetwork != null && activeNetwork.getType() == networkType) {
- final int userid = context.getUserId();
- mMetered = false;
- mConnectivity =
- !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
- if (mConnectivity) { // No point making the call if we know there's no conn.
- mMetered = connManager.isActiveNetworkMetered();
- }
- updateTrackedTasks(userid);
- }
- } else {
- if (DEBUG) {
- Slog.d(TAG, "Unrecognised action in intent: " + action);
- }
- }
- }
- };
-}
diff --git a/services/core/java/com/android/server/task/controllers/TaskStatus.java b/services/core/java/com/android/server/task/controllers/TaskStatus.java
deleted file mode 100644
index 33670a1..0000000
--- a/services/core/java/com/android/server/task/controllers/TaskStatus.java
+++ /dev/null
@@ -1,223 +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.server.task.controllers;
-
-import android.app.task.Task;
-import android.content.ComponentName;
-import android.os.PersistableBundle;
-import android.os.SystemClock;
-import android.os.UserHandle;
-
-import java.io.PrintWriter;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Uniquely identifies a task internally.
- * Created from the public {@link android.app.task.Task} object when it lands on the scheduler.
- * Contains current state of the requirements of the task, as well as a function to evaluate
- * whether it's ready to run.
- * This object is shared among the various controllers - hence why the different fields are atomic.
- * This isn't strictly necessary because each controller is only interested in a specific field,
- * and the receivers that are listening for global state change will all run on the main looper,
- * but we don't enforce that so this is safer.
- * @hide
- */
-public class TaskStatus {
- public static final long DEFAULT_LATEST_RUNTIME = Long.MAX_VALUE;
- public static final long DEFAULT_EARLIEST_RUNTIME = 0L;
-
- final Task task;
- final int uId;
-
- /** At reschedule time we need to know whether to update task on disk. */
- final boolean persisted;
-
- // Constraints.
- final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean timeDelayConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean deadlineConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean idleConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean meteredConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean connectivityConstraintSatisfied = new AtomicBoolean();
-
- /**
- * Earliest point in the future at which this task will be eligible to run. A value of 0
- * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
- */
- private long earliestRunTimeElapsedMillis;
- /**
- * Latest point in the future at which this task must be run. A value of {@link Long#MAX_VALUE}
- * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
- */
- private long latestRunTimeElapsedMillis;
- /** How many times this task has failed, used to compute back-off. */
- private final int numFailures;
-
- /** Provide a handle to the service that this task will be run on. */
- public int getServiceToken() {
- return uId;
- }
-
- private TaskStatus(Task task, int uId, boolean persisted, int numFailures) {
- this.task = task;
- this.uId = uId;
- this.numFailures = numFailures;
- this.persisted = persisted;
- }
-
- /** Create a newly scheduled task. */
- public TaskStatus(Task task, int uId, boolean persisted) {
- this(task, uId, persisted, 0);
-
- final long elapsedNow = SystemClock.elapsedRealtime();
-
- if (task.isPeriodic()) {
- earliestRunTimeElapsedMillis = elapsedNow;
- latestRunTimeElapsedMillis = elapsedNow + task.getIntervalMillis();
- } else {
- earliestRunTimeElapsedMillis = task.hasEarlyConstraint() ?
- elapsedNow + task.getMinLatencyMillis() : DEFAULT_EARLIEST_RUNTIME;
- latestRunTimeElapsedMillis = task.hasLateConstraint() ?
- elapsedNow + task.getMaxExecutionDelayMillis() : DEFAULT_LATEST_RUNTIME;
- }
- }
-
- /**
- * Create a new TaskStatus that was loaded from disk. We ignore the provided
- * {@link android.app.task.Task} time criteria because we can load a persisted periodic task
- * from the {@link com.android.server.task.TaskStore} and still want to respect its
- * wallclock runtime rather than resetting it on every boot.
- * We consider a freshly loaded task to no longer be in back-off.
- */
- public TaskStatus(Task task, int uId, long earliestRunTimeElapsedMillis,
- long latestRunTimeElapsedMillis) {
- this(task, uId, true, 0);
-
- this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
- this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
- }
-
- /** Create a new task to be rescheduled with the provided parameters. */
- public TaskStatus(TaskStatus rescheduling, long newEarliestRuntimeElapsedMillis,
- long newLatestRuntimeElapsedMillis, int backoffAttempt) {
- this(rescheduling.task, rescheduling.getUid(), rescheduling.isPersisted(), backoffAttempt);
-
- earliestRunTimeElapsedMillis = newEarliestRuntimeElapsedMillis;
- latestRunTimeElapsedMillis = newLatestRuntimeElapsedMillis;
- }
-
- public Task getTask() {
- return task;
- }
-
- public int getTaskId() {
- return task.getId();
- }
-
- public int getNumFailures() {
- return numFailures;
- }
-
- public ComponentName getServiceComponent() {
- return task.getService();
- }
-
- public int getUserId() {
- return UserHandle.getUserId(uId);
- }
-
- public int getUid() {
- return uId;
- }
-
- public PersistableBundle getExtras() {
- return task.getExtras();
- }
-
- public boolean hasConnectivityConstraint() {
- return task.getNetworkCapabilities() == Task.NetworkType.ANY;
- }
-
- public boolean hasMeteredConstraint() {
- return task.getNetworkCapabilities() == Task.NetworkType.UNMETERED;
- }
-
- public boolean hasChargingConstraint() {
- return task.isRequireCharging();
- }
-
- public boolean hasTimingDelayConstraint() {
- return earliestRunTimeElapsedMillis != DEFAULT_EARLIEST_RUNTIME;
- }
-
- public boolean hasDeadlineConstraint() {
- return latestRunTimeElapsedMillis != DEFAULT_LATEST_RUNTIME;
- }
-
- public boolean hasIdleConstraint() {
- return task.isRequireDeviceIdle();
- }
-
- public long getEarliestRunTime() {
- return earliestRunTimeElapsedMillis;
- }
-
- public long getLatestRunTimeElapsed() {
- return latestRunTimeElapsedMillis;
- }
-
- public boolean isPersisted() {
- return persisted;
- }
- /**
- * @return Whether or not this task is ready to run, based on its requirements.
- */
- public synchronized boolean isReady() {
- return (!hasChargingConstraint() || chargingConstraintSatisfied.get())
- && (!hasTimingDelayConstraint() || timeDelayConstraintSatisfied.get())
- && (!hasConnectivityConstraint() || connectivityConstraintSatisfied.get())
- && (!hasMeteredConstraint() || meteredConstraintSatisfied.get())
- && (!hasIdleConstraint() || idleConstraintSatisfied.get())
- && (!hasDeadlineConstraint() || deadlineConstraintSatisfied.get());
- }
-
- @Override
- public int hashCode() {
- int result = getServiceComponent().hashCode();
- result = 31 * result + task.getId();
- result = 31 * result + uId;
- return result;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof TaskStatus)) return false;
-
- TaskStatus that = (TaskStatus) o;
- return ((task.getId() == that.task.getId())
- && (uId == that.uId)
- && (getServiceComponent().equals(that.getServiceComponent())));
- }
-
- // Dumpsys infrastructure
- public void dump(PrintWriter pw, String prefix) {
- pw.print(prefix); pw.print("Task "); pw.println(task.getId());
- pw.print(prefix); pw.print("uid="); pw.println(uId);
- pw.print(prefix); pw.print("component="); pw.println(task.getService());
- }
-}
diff --git a/services/core/java/com/android/server/task/controllers/TimeController.java b/services/core/java/com/android/server/task/controllers/TimeController.java
deleted file mode 100644
index 8c6dd27..0000000
--- a/services/core/java/com/android/server/task/controllers/TimeController.java
+++ /dev/null
@@ -1,242 +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.server.task.controllers;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.SystemClock;
-
-import com.android.server.task.StateChangedListener;
-import com.android.server.task.TaskManagerService;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-
-/**
- * This class sets an alarm for the next expiring task, and determines whether a task's minimum
- * delay has been satisfied.
- */
-public class TimeController extends StateController {
- private static final String TAG = "TaskManager.Time";
- private static final String ACTION_TASK_EXPIRED =
- "android.content.taskmanager.TASK_EXPIRED";
- private static final String ACTION_TASK_DELAY_EXPIRED =
- "android.content.taskmanager.TASK_DELAY_EXPIRED";
-
- /** Set an alarm for the next task expiry. */
- private final PendingIntent mTaskExpiredAlarmIntent;
- /** Set an alarm for the next task delay expiry. This*/
- private final PendingIntent mNextDelayExpiredAlarmIntent;
-
- private long mNextTaskExpiredElapsedMillis;
- private long mNextDelayExpiredElapsedMillis;
-
- private AlarmManager mAlarmService = null;
- /** List of tracked tasks, sorted asc. by deadline */
- private final List<TaskStatus> mTrackedTasks = new LinkedList<TaskStatus>();
- /** Singleton. */
- private static TimeController mSingleton;
-
- public static synchronized TimeController get(TaskManagerService taskManager) {
- if (mSingleton == null) {
- mSingleton = new TimeController(taskManager, taskManager.getContext());
- }
- return mSingleton;
- }
-
- private TimeController(StateChangedListener stateChangedListener, Context context) {
- super(stateChangedListener, context);
- mTaskExpiredAlarmIntent =
- PendingIntent.getBroadcast(mContext, 0 /* ignored */,
- new Intent(ACTION_TASK_EXPIRED), 0);
- mNextDelayExpiredAlarmIntent =
- PendingIntent.getBroadcast(mContext, 0 /* ignored */,
- new Intent(ACTION_TASK_DELAY_EXPIRED), 0);
-
- // Register BR for these intents.
- IntentFilter intentFilter = new IntentFilter(ACTION_TASK_EXPIRED);
- intentFilter.addAction(ACTION_TASK_DELAY_EXPIRED);
- mContext.registerReceiver(mAlarmExpiredReceiver, intentFilter);
- }
-
- /**
- * Check if the task has a timing constraint, and if so determine where to insert it in our
- * list.
- */
- @Override
- public synchronized void maybeStartTrackingTask(TaskStatus task) {
- if (task.hasTimingDelayConstraint()) {
- ListIterator<TaskStatus> it = mTrackedTasks.listIterator(mTrackedTasks.size());
- while (it.hasPrevious()) {
- TaskStatus ts = it.previous();
- if (ts.equals(task)) {
- // Update
- it.remove();
- it.add(task);
- break;
- } else if (ts.getLatestRunTimeElapsed() < task.getLatestRunTimeElapsed()) {
- // Insert
- it.add(task);
- break;
- }
- }
- maybeUpdateAlarms(task.getEarliestRunTime(), task.getLatestRunTimeElapsed());
- }
- }
-
- /**
- * If the task passed in is being tracked, figure out if we need to update our alarms, and if
- * so, update them.
- */
- @Override
- public synchronized void maybeStopTrackingTask(TaskStatus taskStatus) {
- if (mTrackedTasks.remove(taskStatus)) {
- if (mNextDelayExpiredElapsedMillis <= taskStatus.getEarliestRunTime()) {
- handleTaskDelayExpired();
- }
- if (mNextTaskExpiredElapsedMillis <= taskStatus.getLatestRunTimeElapsed()) {
- handleTaskDeadlineExpired();
- }
- }
- }
-
- /**
- * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a task's
- * delay will expire.
- * This alarm <b>will not</b> wake up the phone.
- */
- private void setDelayExpiredAlarm(long alarmTimeElapsedMillis) {
- ensureAlarmService();
- mAlarmService.set(AlarmManager.ELAPSED_REALTIME, alarmTimeElapsedMillis,
- mNextDelayExpiredAlarmIntent);
- }
-
- /**
- * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a task's
- * deadline will expire.
- * This alarm <b>will</b> wake up the phone.
- */
- private void setDeadlineExpiredAlarm(long alarmTimeElapsedMillis) {
- ensureAlarmService();
- mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsedMillis,
- mTaskExpiredAlarmIntent);
- }
-
- /**
- * Determines whether this controller can stop tracking the given task.
- * The controller is no longer interested in a task once its time constraint is satisfied, and
- * the task's deadline is fulfilled - unlike other controllers a time constraint can't toggle
- * back and forth.
- */
- private boolean canStopTrackingTask(TaskStatus taskStatus) {
- return (!taskStatus.hasTimingDelayConstraint() ||
- taskStatus.timeDelayConstraintSatisfied.get()) &&
- (!taskStatus.hasDeadlineConstraint() ||
- taskStatus.deadlineConstraintSatisfied.get());
- }
-
- private void maybeUpdateAlarms(long delayExpiredElapsed, long deadlineExpiredElapsed) {
- if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
- mNextDelayExpiredElapsedMillis = delayExpiredElapsed;
- setDelayExpiredAlarm(mNextDelayExpiredElapsedMillis);
- }
- if (deadlineExpiredElapsed < mNextTaskExpiredElapsedMillis) {
- mNextTaskExpiredElapsedMillis = deadlineExpiredElapsed;
- setDeadlineExpiredAlarm(mNextTaskExpiredElapsedMillis);
- }
- }
-
- private void ensureAlarmService() {
- if (mAlarmService == null) {
- mAlarmService = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- }
- }
-
- /**
- * Handles alarm that notifies that a task has expired. When this function is called at least
- * one task must be run.
- */
- private synchronized void handleTaskDeadlineExpired() {
- long nextExpiryTime = Long.MAX_VALUE;
- final long nowElapsedMillis = SystemClock.elapsedRealtime();
-
- Iterator<TaskStatus> it = mTrackedTasks.iterator();
- while (it.hasNext()) {
- TaskStatus ts = it.next();
- final long taskDeadline = ts.getLatestRunTimeElapsed();
-
- if (taskDeadline <= nowElapsedMillis) {
- ts.deadlineConstraintSatisfied.set(true);
- mStateChangedListener.onTaskDeadlineExpired(ts);
- it.remove();
- } else { // Sorted by expiry time, so take the next one and stop.
- nextExpiryTime = taskDeadline;
- break;
- }
- }
- maybeUpdateAlarms(Long.MAX_VALUE, nextExpiryTime);
- }
-
- /**
- * Handles alarm that notifies us that a task's delay has expired. Iterates through the list of
- * tracked tasks and marks them as ready as appropriate.
- */
- private synchronized void handleTaskDelayExpired() {
- final long nowElapsedMillis = SystemClock.elapsedRealtime();
- long nextDelayTime = Long.MAX_VALUE;
-
- Iterator<TaskStatus> it = mTrackedTasks.iterator();
- while (it.hasNext()) {
- final TaskStatus ts = it.next();
- if (!ts.hasTimingDelayConstraint()) {
- continue;
- }
- final long taskDelayTime = ts.getEarliestRunTime();
- if (taskDelayTime < nowElapsedMillis) {
- ts.timeDelayConstraintSatisfied.set(true);
- if (canStopTrackingTask(ts)) {
- it.remove();
- }
- } else { // Keep going through list to get next delay time.
- if (nextDelayTime > taskDelayTime) {
- nextDelayTime = taskDelayTime;
- }
- }
- }
- mStateChangedListener.onControllerStateChanged();
- maybeUpdateAlarms(nextDelayTime, Long.MAX_VALUE);
- }
-
- private final BroadcastReceiver mAlarmExpiredReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- // An task has just expired, so we run through the list of tasks that we have and
- // notify our StateChangedListener.
- if (ACTION_TASK_EXPIRED.equals(intent.getAction())) {
- handleTaskDeadlineExpired();
- } else if (ACTION_TASK_DELAY_EXPIRED.equals(intent.getAction())) {
- handleTaskDelayExpired();
- }
- }
- };
-}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 32546df..b9ef492 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -186,12 +186,16 @@
if (resolveInfo.serviceInfo == null) continue;
String packageName = resolveInfo.serviceInfo.packageName;
+ // STOPSHIP Reenable this check once the GMS Core prebuild library has the
+ // permission.
+ /*
if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName)
!= PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "Skipping agent because package " + packageName
+ " does not have permission " + PERMISSION_PROVIDE_AGENT + ".");
continue;
}
+ */
ComponentName name = getComponentName(resolveInfo);
if (!enabledAgents.contains(name)) continue;
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 1c277a8..10a67c4 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -301,9 +301,8 @@
Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(
userState.inputMap.get(inputId).getComponent());
- mContext.bindServiceAsUser(i, serviceState.mConnection, Context.BIND_AUTO_CREATE,
- new UserHandle(userId));
- serviceState.mBound = true;
+ serviceState.mBound = mContext.bindServiceAsUser(
+ i, serviceState.mConnection, Context.BIND_AUTO_CREATE, new UserHandle(userId));
} else if (serviceState.mService != null && isStateEmpty) {
// This means that the service is already connected but its state indicates that we have
// nothing to do with it. Then, disconnect the service.
diff --git a/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java b/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
index 55dd4ab..24318df 100644
--- a/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
@@ -42,6 +42,7 @@
private static final String seappContextsPath = "seapp_contexts";
private static final String versionPath = "selinux_version";
private static final String macPermissionsPath = "mac_permissions.xml";
+ private static final String serviceContextsPath = "service_contexts";
public SELinuxPolicyInstallReceiver() {
super("/data/security/bundle", "sepolicy_bundle", "metadata/", "version");
@@ -65,6 +66,9 @@
new File(contexts, sepolicyPath).renameTo(
new File(contexts, sepolicyPath + "_backup"));
+
+ new File(contexts, serviceContextsPath).renameTo(
+ new File(contexts, serviceContextsPath + "_backup"));
}
private void copyUpdate(File contexts) {
@@ -74,6 +78,7 @@
new File(updateDir, propertyContextsPath).renameTo(new File(contexts, propertyContextsPath));
new File(updateDir, fileContextsPath).renameTo(new File(contexts, fileContextsPath));
new File(updateDir, sepolicyPath).renameTo(new File(contexts, sepolicyPath));
+ new File(updateDir, serviceContextsPath).renameTo(new File(contexts, serviceContextsPath));
}
private int readInt(BufferedInputStream reader) throws IOException {
@@ -85,13 +90,14 @@
}
private int[] readChunkLengths(BufferedInputStream bundle) throws IOException {
- int[] chunks = new int[6];
+ int[] chunks = new int[7];
chunks[0] = readInt(bundle);
chunks[1] = readInt(bundle);
chunks[2] = readInt(bundle);
chunks[3] = readInt(bundle);
chunks[4] = readInt(bundle);
chunks[5] = readInt(bundle);
+ chunks[6] = readInt(bundle);
return chunks;
}
@@ -112,6 +118,7 @@
installFile(new File(updateDir, propertyContextsPath), stream, chunkLengths[3]);
installFile(new File(updateDir, fileContextsPath), stream, chunkLengths[4]);
installFile(new File(updateDir, sepolicyPath), stream, chunkLengths[5]);
+ installFile(new File(updateDir, serviceContextsPath), stream, chunkLengths[6]);
} finally {
IoUtils.closeQuietly(stream);
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index cfd09e5..d05d0c7 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -44,6 +44,7 @@
import android.view.Surface;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
+import android.view.ViewConfiguration;
import android.view.WindowInfo;
import android.view.WindowManager;
import android.view.WindowManagerInternal.MagnificationCallbacks;
@@ -113,13 +114,13 @@
mDisplayMagnifier.setMagnificationSpecLocked(spec);
}
if (mWindowsForAccessibilityObserver != null) {
- mWindowsForAccessibilityObserver.computeChangedWindows();
+ mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
}
}
- public void onRectangleOnScreenRequestedLocked(Rect rectangle, boolean immediate) {
+ public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
if (mDisplayMagnifier != null) {
- mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle, immediate);
+ mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
}
// Not relevant for the window observer.
}
@@ -129,7 +130,7 @@
mDisplayMagnifier.onWindowLayersChangedLocked();
}
if (mWindowsForAccessibilityObserver != null) {
- mWindowsForAccessibilityObserver.computeChangedWindows();
+ mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
}
}
@@ -138,7 +139,7 @@
mDisplayMagnifier.onRotationChangedLocked(displayContent, rotation);
}
if (mWindowsForAccessibilityObserver != null) {
- mWindowsForAccessibilityObserver.computeChangedWindows();
+ mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
}
}
@@ -154,7 +155,7 @@
mDisplayMagnifier.onWindowTransitionLocked(windowState, transition);
}
if (mWindowsForAccessibilityObserver != null) {
- mWindowsForAccessibilityObserver.computeChangedWindows();
+ mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
}
}
@@ -162,7 +163,16 @@
// Not relevant for the display magnifier.
if (mWindowsForAccessibilityObserver != null) {
- mWindowsForAccessibilityObserver.computeChangedWindows();
+ mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
+ }
+ }
+
+
+ public void onSomeWindowResizedOrMovedLocked() {
+ // Not relevant for the display magnifier.
+
+ if (mWindowsForAccessibilityObserver != null) {
+ mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
}
}
@@ -247,7 +257,7 @@
mWindowManagerService.scheduleAnimationLocked();
}
- public void onRectangleOnScreenRequestedLocked(Rect rectangle, boolean immediate) {
+ public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
if (DEBUG_RECTANGLE_REQUESTED) {
Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
}
@@ -880,21 +890,45 @@
private final WindowsForAccessibilityCallback mCallback;
+ private final long mRecurringAccessibilityEventsIntervalMillis;
+
public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
WindowsForAccessibilityCallback callback) {
mContext = windowManagerService.mContext;
mWindowManagerService = windowManagerService;
mCallback = callback;
mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
+ mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
+ .getSendRecurringAccessibilityEventsInterval();
computeChangedWindows();
}
+ public void scheduleComputeChangedWindowsLocked() {
+ // If focus changed, compute changed windows immediately as the focused window
+ // is used by the accessibility manager service to determine the active window.
+ if (mWindowManagerService.mCurrentFocus != null
+ && mWindowManagerService.mCurrentFocus != mWindowManagerService.mLastFocus) {
+ mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
+ computeChangedWindows();
+ } else if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
+ mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
+ mRecurringAccessibilityEventsIntervalMillis);
+ }
+ }
+
public void computeChangedWindows() {
if (DEBUG) {
Slog.i(LOG_TAG, "computeChangedWindows()");
}
synchronized (mWindowManagerService.mWindowMap) {
+ // Do not send the windows if there is no current focus as
+ // the window manager is still looking for where to put it.
+ // We will do the work when we get a focus change callback.
+ if (mWindowManagerService.mCurrentFocus == null) {
+ return;
+ }
+
WindowManager windowManager = (WindowManager)
mContext.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getRealSize(mTempPoint);
@@ -912,39 +946,21 @@
Set<IBinder> addedWindows = mTempBinderSet;
addedWindows.clear();
+ boolean focusedWindowAdded = false;
+
final int visibleWindowCount = visibleWindows.size();
for (int i = visibleWindowCount - 1; i >= 0; i--) {
WindowState windowState = visibleWindows.valueAt(i);
- // Compute the window touchable frame as shown on the screen.
- // Get the touchable frame.
- Region touchableRegion = mTempRegion1;
- windowState.getTouchableRegion(touchableRegion);
- Rect touchableFrame = mTempRect;
- touchableRegion.getBounds(touchableFrame);
-
- // Move to origin as all transforms are captured by the matrix.
- RectF windowFrame = mTempRectF;
- windowFrame.set(touchableFrame);
- windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
-
- // Map the frame to get what appears on the screen.
- Matrix matrix = mTempMatrix;
- populateTransformationMatrixLocked(windowState, matrix);
- matrix.mapRect(windowFrame);
-
- // Got the bounds.
+ // Compute the bounds in the screen.
Rect boundsInScreen = mTempRect;
- boundsInScreen.set((int) windowFrame.left, (int) windowFrame.top,
- (int) windowFrame.right, (int) windowFrame.bottom);
+ computeWindowBoundsInScreen(windowState, boundsInScreen);
final int flags = windowState.mAttrs.flags;
// If the window is not touchable, do not report it but take into account
// the space it takes since the content behind it cannot be touched.
- if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) == 1) {
- unaccountedSpace.op(boundsInScreen, unaccountedSpace,
- Region.Op.DIFFERENCE);
+ if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
continue;
}
@@ -956,33 +972,12 @@
// Add windows of certain types not covered by modal windows.
if (isReportedWindowType(windowState.mAttrs.type)) {
// Add the window to the ones to be reported.
- WindowInfo window = WindowInfo.obtain();
- window.type = windowState.mAttrs.type;
- window.layer = windowState.mLayer;
- window.token = windowState.mClient.asBinder();
-
+ WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen);
addedWindows.add(window.token);
-
- WindowState attachedWindow = windowState.mAttachedWindow;
- if (attachedWindow != null) {
- window.parentToken = attachedWindow.mClient.asBinder();
- }
-
- window.focused = windowState.isFocused();
- window.boundsInScreen.set(boundsInScreen);
-
- final int childCount = windowState.mChildWindows.size();
- if (childCount > 0) {
- if (window.childTokens == null) {
- window.childTokens = new ArrayList<IBinder>();
- }
- for (int j = 0; j < childCount; j++) {
- WindowState child = windowState.mChildWindows.get(j);
- window.childTokens.add(child.mClient.asBinder());
- }
- }
-
windows.add(window);
+ if (windowState.isFocused()) {
+ focusedWindowAdded = true;
+ }
}
// Account for the space this window takes.
@@ -1001,6 +996,25 @@
}
}
+ // Always report the focused window.
+ if (!focusedWindowAdded) {
+ for (int i = visibleWindowCount - 1; i >= 0; i--) {
+ WindowState windowState = visibleWindows.valueAt(i);
+ if (windowState.isFocused()) {
+ // Compute the bounds in the screen.
+ Rect boundsInScreen = mTempRect;
+ computeWindowBoundsInScreen(windowState, boundsInScreen);
+
+ // Add the window to the ones to be reported.
+ WindowInfo window = obtainPopulatedWindowInfo(windowState,
+ boundsInScreen);
+ addedWindows.add(window.token);
+ windows.add(window);
+ break;
+ }
+ }
+ }
+
// Remove child/parent references to windows that were not added.
final int windowCount = windows.size();
for (int i = 0; i < windowCount; i++) {
@@ -1063,6 +1077,57 @@
}
}
+ private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
+ // Get the touchable frame.
+ Region touchableRegion = mTempRegion1;
+ windowState.getTouchableRegion(touchableRegion);
+ Rect touchableFrame = mTempRect;
+ touchableRegion.getBounds(touchableFrame);
+
+ // Move to origin as all transforms are captured by the matrix.
+ RectF windowFrame = mTempRectF;
+ windowFrame.set(touchableFrame);
+ windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
+
+ // Map the frame to get what appears on the screen.
+ Matrix matrix = mTempMatrix;
+ populateTransformationMatrixLocked(windowState, matrix);
+ matrix.mapRect(windowFrame);
+
+ // Got the bounds.
+ outBounds.set((int) windowFrame.left, (int) windowFrame.top,
+ (int) windowFrame.right, (int) windowFrame.bottom);
+ }
+
+ private static WindowInfo obtainPopulatedWindowInfo(WindowState windowState,
+ Rect boundsInScreen) {
+ WindowInfo window = WindowInfo.obtain();
+ window.type = windowState.mAttrs.type;
+ window.layer = windowState.mLayer;
+ window.token = windowState.mClient.asBinder();
+
+ WindowState attachedWindow = windowState.mAttachedWindow;
+ if (attachedWindow != null) {
+ window.parentToken = attachedWindow.mClient.asBinder();
+ }
+
+ window.focused = windowState.isFocused();
+ window.boundsInScreen.set(boundsInScreen);
+
+ final int childCount = windowState.mChildWindows.size();
+ if (childCount > 0) {
+ if (window.childTokens == null) {
+ window.childTokens = new ArrayList<IBinder>();
+ }
+ for (int j = 0; j < childCount; j++) {
+ WindowState child = windowState.mChildWindows.get(j);
+ window.childTokens.add(child.mClient.asBinder());
+ }
+ }
+
+ return window;
+ }
+
private void cacheWindows(List<WindowInfo> windows) {
final int oldWindowCount = mOldWindows.size();
for (int i = oldWindowCount - 1; i >= 0; i--) {
@@ -1079,10 +1144,10 @@
if (oldWindow == newWindow) {
return false;
}
- if (oldWindow == null && newWindow != null) {
+ if (oldWindow == null) {
return true;
}
- if (oldWindow != null && newWindow == null) {
+ if (newWindow == null) {
return true;
}
if (oldWindow.type != newWindow.type) {
@@ -1151,7 +1216,8 @@
}
private class MyHandler extends Handler {
- public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED = 1;
+ public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
+ public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED = 2;
public MyHandler(Looper looper) {
super(looper, null, false);
@@ -1161,6 +1227,10 @@
@SuppressWarnings("unchecked")
public void handleMessage(Message message) {
switch (message.what) {
+ case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
+ computeChangedWindows();
+ } break;
+
case MESSAGE_NOTIFY_WINDOWS_CHANGED: {
List<WindowInfo> windows = (List<WindowInfo>) message.obj;
mCallback.onWindowsForAccessibilityChanged(windows);
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
deleted file mode 100644
index 29bab22..0000000
--- a/services/core/java/com/android/server/wm/CircularDisplayMask.java
+++ /dev/null
@@ -1,133 +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.server.wm;
-
-
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.view.Display;
-import android.view.Surface;
-import android.view.Surface.OutOfResourcesException;
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-
-class CircularDisplayMask {
- private static final String TAG = "CircularDisplayMask";
-
- private static final int STROKE_WIDTH = 2;
- // half the screen size
- private static final int CIRCLE_RADIUS = 160;
- // size of the chin
- private static final int SCREEN_OFFSET = 30;
-
- private final SurfaceControl mSurfaceControl;
- private final Surface mSurface = new Surface();
- private int mLastDW;
- private int mLastDH;
- private boolean mDrawNeeded;
- private Paint mPaint;
- private int mRotation;
- private boolean mVisible;
-
- public CircularDisplayMask(Display display, SurfaceSession session, int zOrder) {
- SurfaceControl ctrl = null;
- try {
- ctrl = new SurfaceControl(session, "CircularDisplayMask",
- 320, 320, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
- ctrl.setLayerStack(display.getLayerStack());
- ctrl.setLayer(zOrder);
- ctrl.setPosition(0, 0);
- ctrl.show();
- mSurface.copyFrom(ctrl);
- } catch (OutOfResourcesException e) {
- }
- mSurfaceControl = ctrl;
- mDrawNeeded = true;
- mPaint = new Paint();
- mPaint.setAntiAlias(true);
- mPaint.setStyle(Paint.Style.STROKE);
- mPaint.setColor(Color.BLACK);
- mPaint.setStrokeWidth(STROKE_WIDTH);
- }
-
- private void drawIfNeeded() {
- if (!mDrawNeeded || !mVisible) {
- return;
- }
- mDrawNeeded = false;
-
- Rect dirty = new Rect(0, 0, 320, 320);
- Canvas c = null;
- try {
- c = mSurface.lockCanvas(dirty);
- } catch (IllegalArgumentException e) {
- } catch (Surface.OutOfResourcesException e) {
- }
- if (c == null) {
- return;
- }
- c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC);
- switch (mRotation) {
- case Surface.ROTATION_0:
- case Surface.ROTATION_90:
- // chin bottom or right
- mSurfaceControl.setPosition(0, 0);
- break;
- case Surface.ROTATION_180:
- // chin top
- mSurfaceControl.setPosition(0, -SCREEN_OFFSET);
- break;
- case Surface.ROTATION_270:
- // chin left
- mSurfaceControl.setPosition(-SCREEN_OFFSET, 0);
- break;
- }
- c.drawCircle(CIRCLE_RADIUS, CIRCLE_RADIUS, CIRCLE_RADIUS, mPaint);
- mSurface.unlockCanvasAndPost(c);
- }
-
- // Note: caller responsible for being inside
- // Surface.openTransaction() / closeTransaction()
- public void setVisibility(boolean on) {
- if (mSurfaceControl == null) {
- return;
- }
- mVisible = on;
- drawIfNeeded();
- if (on) {
- mSurfaceControl.show();
- } else {
- mSurfaceControl.hide();
- }
- }
-
- void positionSurface(int dw, int dh, int rotation) {
- if (mLastDW == dw && mLastDH == dh && mRotation == rotation) {
- return;
- }
- mLastDW = dw;
- mLastDH = dh;
- mDrawNeeded = true;
- mRotation = rotation;
- drawIfNeeded();
- }
-
-}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 3200b54..b4cf2ae 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -446,11 +446,11 @@
}
}
- public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) {
+ public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
synchronized(mService.mWindowMap) {
final long identity = Binder.clearCallingIdentity();
try {
- mService.onRectangleOnScreenRequested(token, rectangle, immediate);
+ mService.onRectangleOnScreenRequested(token, rectangle);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index a354c45..dfb1200 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -154,7 +154,8 @@
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
- if (windows.get(winNdx).mWinAnimator.isAnimating()) {
+ final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
+ if (winAnimator.isAnimating() && !winAnimator.isDummyAnimation()) {
return true;
}
}
@@ -236,9 +237,22 @@
void detachDisplay() {
EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
+
+ boolean doAnotherLayoutPass = false;
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
- mService.tmpRemoveTaskWindowsLocked(mTasks.get(taskNdx));
+ final AppTokenList appWindowTokens = mTasks.get(taskNdx).mAppTokens;
+ for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) {
+ final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows;
+ for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
+ mService.removeWindowInnerLocked(null, appWindows.get(winNdx));
+ doAnotherLayoutPass = true;
+ }
+ }
}
+ if (doAnotherLayoutPass) {
+ mService.requestTraversalLocked();
+ }
+
mAnimationBackgroundSurface.destroySurface();
mAnimationBackgroundSurface = null;
mDimLayer.destroySurface();
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 008d2fc..45326f7 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -19,6 +19,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static com.android.server.wm.WindowManagerService.LayoutFields.SET_UPDATE_ROTATION;
import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_MAY_CHANGE;
import static com.android.server.wm.WindowManagerService.LayoutFields.SET_FORCE_HIDING_CHANGED;
@@ -227,7 +228,7 @@
continue;
}
final WindowStateAnimator winAnimator = win.mWinAnimator;
- if (mPolicy.doesForceHide(win.mAttrs)) {
+ if ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
if (!winAnimator.mAnimating) {
// Create a new animation to delay until keyguard is gone on its own.
winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f);
@@ -268,7 +269,7 @@
}
}
- if (mPolicy.doesForceHide(win.mAttrs)) {
+ if (mPolicy.isForceHiding(win.mAttrs)) {
if (!wasAnimating && nowAnimating) {
if (WindowManagerService.DEBUG_ANIM ||
WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2d15dab..2d8a34b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -151,7 +151,6 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -433,7 +432,6 @@
final SurfaceSession mFxSession;
Watermark mWatermark;
StrictModeFlash mStrictModeFlash;
- CircularDisplayMask mCircularDisplayMask;
FocusedStackFrame mFocusedStackFrame;
int mFocusedStackLayer;
@@ -846,8 +844,6 @@
} finally {
SurfaceControl.closeTransaction();
}
-
- showCircularDisplayMaskIfNeeded();
}
public InputMonitor getInputMonitor() {
@@ -1487,10 +1483,15 @@
if (pos >= 0) {
final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken;
- if (pos < windows.size()) {
- WindowState wp = windows.get(pos);
- if (wp == mInputMethodWindow) {
- pos++;
+ // Skip windows owned by the input method.
+ if (mInputMethodWindow != null) {
+ while (pos < windows.size()) {
+ WindowState wp = windows.get(pos);
+ if (wp == mInputMethodWindow || wp.mAttachedWindow == mInputMethodWindow) {
+ pos++;
+ continue;
+ }
+ break;
}
}
if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Adding " + N + " dialogs at pos=" + pos);
@@ -2528,7 +2529,7 @@
Binder.restoreCallingIdentity(origId);
}
- private void removeWindowInnerLocked(Session session, WindowState win) {
+ void removeWindowInnerLocked(Session session, WindowState win) {
if (win.mRemoved) {
// Nothing to do.
return;
@@ -2810,14 +2811,13 @@
performLayoutAndPlaceSurfacesLocked();
}
- public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) {
+ public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
synchronized (mWindowMap) {
if (mAccessibilityController != null) {
WindowState window = mWindowMap.get(token);
//TODO (multidisplay): Magnification is supported only for the default display.
if (window != null && window.getDisplayId() == Display.DEFAULT_DISPLAY) {
- mAccessibilityController.onRectangleOnScreenRequestedLocked(rectangle,
- immediate);
+ mAccessibilityController.onRectangleOnScreenRequestedLocked(rectangle);
}
}
}
@@ -5574,39 +5574,6 @@
}
}
- public void showCircularDisplayMaskIfNeeded() {
- // we're fullscreen and not hosted in an ActivityView
- if (mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_windowIsRound)) {
- mH.sendMessage(mH.obtainMessage(H.SHOW_DISPLAY_MASK));
- }
- }
-
- public void showCircularMask() {
- synchronized(mWindowMap) {
-
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
- ">>> OPEN TRANSACTION showDisplayMask");
- SurfaceControl.openTransaction();
- try {
- // TODO(multi-display): support multiple displays
- if (mCircularDisplayMask == null) {
- mCircularDisplayMask = new CircularDisplayMask(
- getDefaultDisplayContentLocked().getDisplay(),
- mFxSession,
- mPolicy.windowTypeToLayerLw(
- WindowManager.LayoutParams.TYPE_POINTER)
- * TYPE_LAYER_MULTIPLIER + 10);
- }
- mCircularDisplayMask.setVisibility(true);
- } finally {
- SurfaceControl.closeTransaction();
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
- "<<< CLOSE TRANSACTION showDisplayMask");
- }
- }
- }
-
// TODO: more accounting of which pid(s) turned it on, keep count,
// only allow disables from pids which have count on, etc.
@Override
@@ -7213,10 +7180,9 @@
public static final int TAP_OUTSIDE_STACK = 31;
public static final int NOTIFY_ACTIVITY_DRAWN = 32;
- public static final int SHOW_DISPLAY_MASK = 33;
- public static final int ALL_WINDOWS_DRAWN = 34;
+ public static final int ALL_WINDOWS_DRAWN = 33;
- public static final int NEW_ANIMATOR_SCALE = 35;
+ public static final int NEW_ANIMATOR_SCALE = 34;
@Override
public void handleMessage(Message msg) {
@@ -7615,11 +7581,6 @@
break;
}
- case SHOW_DISPLAY_MASK: {
- showCircularMask();
- break;
- }
-
case DO_ANIMATION_CALLBACK: {
try {
((IRemoteCallback)msg.obj).sendResult(null);
@@ -8481,7 +8442,7 @@
}
win.mLayoutNeeded = false;
win.prelayout();
- mPolicy.layoutWindowLw(win, win.mAttrs, null);
+ mPolicy.layoutWindowLw(win, null);
win.mLayoutSeq = seq;
if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame="
+ win.mFrame + " mContainingFrame="
@@ -8533,7 +8494,7 @@
}
win.mLayoutNeeded = false;
win.prelayout();
- mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
+ mPolicy.layoutWindowLw(win, win.mAttachedWindow);
win.mLayoutSeq = seq;
if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame="
+ win.mFrame + " mContainingFrame="
@@ -9135,9 +9096,6 @@
if (mStrictModeFlash != null) {
mStrictModeFlash.positionSurface(defaultDw, defaultDh);
}
- if (mCircularDisplayMask != null) {
- mCircularDisplayMask.positionSurface(defaultDw, defaultDh, mRotation);
- }
boolean focusDisplayed = false;
@@ -9268,6 +9226,13 @@
winAnimator.setAnimation(a);
winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
+
+ //TODO (multidisplay): Accessibility supported only for the default display.
+ if (mAccessibilityController != null
+ && displayId == Display.DEFAULT_DISPLAY) {
+ mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+ }
+
try {
w.mClient.moved(w.mFrame.left, w.mFrame.top);
} catch (RemoteException e) {
@@ -9906,7 +9871,9 @@
mCurrentFocus = newFocus;
mLosingFocus.remove(newFocus);
- if (mAccessibilityController != null) {
+ // TODO(multidisplay): Accessibilty supported only of default desiplay.
+ if (mAccessibilityController != null
+ && displayContent.getDisplayId() == Display.DEFAULT_DISPLAY) {
mAccessibilityController.onWindowFocusChangedLocked();
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4a80e3e..7003c8c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -36,6 +36,7 @@
import android.os.RemoteCallbackList;
import android.os.SystemClock;
import android.util.TimeUtils;
+import android.view.Display;
import android.view.IWindowFocusObserver;
import android.view.IWindowId;
import com.android.server.input.InputWindowHandle;
@@ -727,8 +728,11 @@
}
public DisplayContent getDisplayContent() {
- return mAppToken == null || mNotOnAppsDisplay ?
- mDisplayContent : getStack().getDisplayContent();
+ if (mAppToken == null || mNotOnAppsDisplay) {
+ return mDisplayContent;
+ }
+ final TaskStack stack = getStack();
+ return stack == null ? mDisplayContent : stack.getDisplayContent();
}
public int getDisplayId() {
@@ -1359,6 +1363,13 @@
mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, reportDraw,
newConfig);
}
+
+ //TODO (multidisplay): Accessibility supported only for the default display.
+ if (mService.mAccessibilityController != null
+ && getDisplayId() == Display.DEFAULT_DISPLAY) {
+ mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+ }
+
mOverscanInsetsChanged = false;
mContentInsetsChanged = false;
mVisibleInsetsChanged = false;
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 3cfb45b..db44d3a 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -12,7 +12,6 @@
$(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
$(LOCAL_REL_DIR)/com_android_server_dreams_McuHal.cpp \
$(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
- $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecService.cpp \
$(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiMhlController.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index a734026..0f919d1 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -57,12 +57,21 @@
int getVersion();
// Get vendor id used for vendor command.
uint32_t getVendorId();
+ // Get Port information on all the HDMI ports.
+ jobjectArray getPortInfos();
+ // Set a flag and its value.
+ void setOption(int flag, int value);
+ // Set audio return channel status.
+ void setAudioReturnChannel(bool flag);
+ // Whether to hdmi device is connected to the given port.
+ bool isConnected(int port);
jobject getCallbacksObj() const {
return mCallbacksObj;
}
private:
+ static const int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
static void onReceived(const hdmi_event_t* event, void* arg);
hdmi_cec_device_t* mDevice;
@@ -203,11 +212,11 @@
}
int HdmiCecController::getPhysicalAddress() {
- uint16_t physicalAddress = 0xFFFF;
- if (mDevice->get_physical_address(mDevice, &physicalAddress) == 0) {
- return physicalAddress;
+ uint16_t addr;
+ if (!mDevice->get_physical_address(mDevice, &addr)) {
+ return addr;
}
- return -1;
+ return INVALID_PHYSICAL_ADDRESS;
}
int HdmiCecController::getVersion() {
@@ -222,6 +231,47 @@
return vendorId;
}
+jobjectArray HdmiCecController::getPortInfos() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jclass hdmiPortInfo = env->FindClass("android/hardware/hdmi/HdmiPortInfo");
+ if (hdmiPortInfo == NULL) {
+ return NULL;
+ }
+ jmethodID ctor = env->GetMethodID(hdmiPortInfo, "<init>", "(IIIZZZ)V");
+ if (ctor == NULL) {
+ return NULL;
+ }
+ hdmi_port_info* ports;
+ int numPorts;
+ mDevice->get_port_info(mDevice, &ports, &numPorts);
+ jobjectArray res = env->NewObjectArray(numPorts, hdmiPortInfo, NULL);
+
+ // MHL support field will be obtained from MHL HAL. Leave it to false.
+ jboolean mhlSupported = (jboolean) 0;
+ for (int i = 0; i < numPorts; ++i) {
+ hdmi_port_info* info = &ports[i];
+ jboolean cecSupported = (jboolean) info->cec_supported;
+ jboolean arcSupported = (jboolean) info->arc_supported;
+ jobject infoObj = env->NewObject(hdmiPortInfo, ctor, info->port_num, info->type,
+ info->physical_address, cecSupported, mhlSupported, arcSupported);
+ env->SetObjectArrayElement(res, i, infoObj);
+ }
+ return res;
+}
+
+void HdmiCecController::setOption(int flag, int value) {
+ mDevice->set_option(mDevice, flag, value);
+}
+
+// Set audio return channel status.
+void HdmiCecController::setAudioReturnChannel(bool enabled) {
+ mDevice->set_audio_return_channel(mDevice, enabled ? 1 : 0);
+}
+
+// Whether to hdmi device is connected to the given port.
+bool HdmiCecController::isConnected(int port) {
+ return mDevice->is_connected(mDevice, port) == HDMI_CONNECTED;
+}
// static
void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) {
@@ -291,41 +341,53 @@
return controller->sendMessage(message);
}
-static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz,
- jlong controllerPtr, jint logicalAddress) {
- HdmiCecController* controller =
- reinterpret_cast<HdmiCecController*>(controllerPtr);
- return controller->addLogicalAddress(
- static_cast<cec_logical_address_t>(logicalAddress));
+static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr,
+ jint logicalAddress) {
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->addLogicalAddress(static_cast<cec_logical_address_t>(logicalAddress));
}
-static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz,
- jlong controllerPtr) {
- HdmiCecController* controller =
- reinterpret_cast<HdmiCecController*>(controllerPtr);
+static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
controller->clearLogicaladdress();
}
-static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz,
- jlong controllerPtr) {
- HdmiCecController* controller =
- reinterpret_cast<HdmiCecController*>(controllerPtr);
+static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
return controller->getPhysicalAddress();
}
-static jint nativeGetVersion(JNIEnv* env, jclass clazz,
- jlong controllerPtr) {
- HdmiCecController* controller =
- reinterpret_cast<HdmiCecController*>(controllerPtr);
+static jint nativeGetVersion(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
return controller->getVersion();
}
static jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) {
- HdmiCecController* controller =
- reinterpret_cast<HdmiCecController*>(controllerPtr);
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
return controller->getVendorId();
}
+static jobjectArray nativeGetPortInfos(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->getPortInfos();
+}
+
+static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, jint value) {
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
+ controller->setOption(flag, value);
+}
+
+static void nativeSetAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
+ jboolean enabled) {
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
+ controller->setAudioReturnChannel(enabled == JNI_TRUE);
+}
+
+static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) {
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ;
+}
+
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit",
@@ -337,13 +399,18 @@
{ "nativeGetPhysicalAddress", "(J)I", (void *) nativeGetPhysicalAddress },
{ "nativeGetVersion", "(J)I", (void *) nativeGetVersion },
{ "nativeGetVendorId", "(J)I", (void *) nativeGetVendorId },
+ { "nativeGetPortInfos",
+ "(J)[Landroid/hardware/hdmi/HdmiPortInfo;",
+ (void *) nativeGetPortInfos },
+ { "nativeSetOption", "(JII)V", (void *) nativeSetOption },
+ { "nativeSetAudioReturnChannel", "(JZ)V", (void *) nativeSetAudioReturnChannel },
+ { "nativeIsConnected", "(JI)Z", (void *) nativeIsConnected },
};
#define CLASS_PATH "com/android/server/hdmi/HdmiCecController"
int register_android_server_hdmi_HdmiCecController(JNIEnv* env) {
- int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods,
- NELEM(sMethods));
+ int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods));
LOG_FATAL_IF(res < 0, "Unable to register native methods.");
return 0;
}
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
deleted file mode 100644
index 1d111a1..0000000
--- a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
+++ /dev/null
@@ -1,756 +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.
- */
-
-#define LOG_TAG "HdmiCecJni"
-
-#define LOG_NDEBUG 1
-
-#include "ScopedPrimitiveArray.h"
-
-#include <string>
-#include <deque>
-#include <map>
-
-#include <android_runtime/AndroidRuntime.h>
-#include <android_runtime/Log.h>
-#include <hardware/hdmi_cec.h>
-
-namespace android {
-
-static struct {
- jmethodID handleMessage;
- jmethodID handleHotplug;
- jmethodID getActiveSource;
- jmethodID getLanguage;
-} gHdmiCecServiceClassInfo;
-
-#ifndef min
-#define min(a, b) ((a) > (b) ? (b) : (a))
-#endif
-
-class HdmiCecHandler {
-public:
- enum HdmiCecError {
- SUCCESS = 0,
- FAILED = -1
- };
-
- // Data type to hold a CEC message or internal event data.
- typedef union {
- cec_message_t cec;
- hotplug_event_t hotplug;
- } queue_item_t;
-
- // Entry used for message queue.
- typedef std::pair<int, const queue_item_t> MessageEntry;
-
- HdmiCecHandler(hdmi_cec_device_t* device, jobject callbacksObj);
-
- void initialize();
-
- // initialize individual logical device.
- cec_logical_address_t initLogicalDevice(cec_device_type_t type);
- void releaseLogicalDevice(cec_device_type_t type);
-
- cec_logical_address_t getLogicalAddress(cec_device_type_t deviceType);
- uint16_t getPhysicalAddress();
- cec_device_type_t getDeviceType(cec_logical_address_t addr);
- void queueMessage(const MessageEntry& message);
- void queueOutgoingMessage(const cec_message_t& message);
- void sendReportPhysicalAddress(cec_logical_address_t srcAddr);
- void sendActiveSource(cec_logical_address_t srcAddr);
- void sendFeatureAbort(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
- int opcode, int reason);
- void sendCecVersion(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
- int version);
- void sendDeviceVendorId(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr);
- void sendGiveDeviceVendorID(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr);
- void sendSetOsdName(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
- const char* name, size_t len);
- void sendSetMenuLanguage(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr);
-
- void sendCecMessage(const cec_message_t& message);
- void setOsdName(const char* name, size_t len);
-
-private:
- enum {
- EVENT_TYPE_RX,
- EVENT_TYPE_TX,
- EVENT_TYPE_HOTPLUG,
- EVENT_TYPE_STANDBY
- };
-
- /*
- * logical address pool for each device type.
- */
- static const cec_logical_address_t TV_ADDR_POOL[];
- static const cec_logical_address_t PLAYBACK_ADDR_POOL[];
- static const cec_logical_address_t RECORDER_ADDR_POOL[];
- static const cec_logical_address_t TUNER_ADDR_POOL[];
-
- static const unsigned int MAX_BUFFER_SIZE = 256;
- static const uint16_t INVALID_PHYSICAL_ADDRESS = 0xFFFF;
-
- static void onReceived(const hdmi_event_t* event, void* arg);
- static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
-
- void updatePhysicalAddress();
- void updateLogicalAddress();
-
- // Allocate logical address. The CEC standard recommends that we try to use the address
- // we have ever used before, in case this is to allocate an address afte the cable is
- // connected again. If preferredAddr is given a valid one (not CEC_ADDR_UNREGISTERED), then
- // this method checks if the address is available first. If not, it tries other addresses
- // int the address pool available for the given type.
- cec_logical_address_t allocateLogicalAddress(cec_device_type_t type,
- cec_logical_address_t preferredAddr);
-
- // Send a CEC ping message. Returns true if successful.
- bool sendPing(cec_logical_address_t addr);
-
- // Return the pool of logical addresses that are used for a given device type.
- // One of the addresses in the pool will be chosen in the allocation logic.
- bool getLogicalAddressPool(cec_device_type_t type, const cec_logical_address_t** addrPool,
- size_t* poolSize);
-
- // Handles the message retrieved from internal message queue. The message can be
- // for either rx or tx.
- void dispatchMessage(const MessageEntry& message);
- void processIncomingMessage(const cec_message_t& msg);
-
- // Check the message before we pass it up to framework. If true, we proceed.
- // otherwise do not propagate it.
- bool precheckMessage(const cec_message_t& msg);
-
- // Propagate the message up to Java layer.
- void propagateMessage(const cec_message_t& msg);
- void propagateHotplug(bool connected);
-
- // Handles incoming <Request Active Source> message. If one of logical
- // devices is active, it should reply with <Active Source> message.
- void handleRequestActiveSource();
- void handleGiveOsdName(const cec_message_t& msg);
- void handleGiveDeviceVendorID(const cec_message_t& msg);
- void handleGetCECVersion(const cec_message_t& msg);
- void handleGetMenuLanguage(const cec_message_t& msg);
-
- // Internal thread for message queue handler
- class HdmiThread : public Thread {
- public:
- HdmiThread(HdmiCecHandler* hdmiCecHandler, bool canCallJava) :
- Thread(canCallJava),
- mHdmiCecHandler(hdmiCecHandler) {
- }
- private:
- virtual bool threadLoop() {
- ALOGV("HdmiThread started");
- AutoMutex _l(mHdmiCecHandler->mMessageQueueLock);
- mHdmiCecHandler->mMessageQueueCondition.wait(mHdmiCecHandler->mMessageQueueLock);
- /* Process all messages in the queue */
- while (mHdmiCecHandler->mMessageQueue.size() > 0) {
- MessageEntry entry = mHdmiCecHandler->mMessageQueue.front();
- mHdmiCecHandler->dispatchMessage(entry);
- }
- return true;
- }
-
- HdmiCecHandler* mHdmiCecHandler;
- };
-
- // device type -> logical address mapping
- std::map<cec_device_type_t, cec_logical_address_t> mLogicalDevices;
-
- hdmi_cec_device_t* mDevice;
- jobject mCallbacksObj;
- Mutex mLock;
- Mutex mMessageQueueLock;
- Condition mMessageQueueCondition;
- sp<HdmiThread> mMessageQueueHandler;
-
- std::deque<MessageEntry> mMessageQueue;
- uint16_t mPhysicalAddress;
- std::string mOsdName;
-};
-
- const cec_logical_address_t HdmiCecHandler::TV_ADDR_POOL[] = {
- CEC_ADDR_TV,
- CEC_ADDR_FREE_USE,
- };
-
- const cec_logical_address_t HdmiCecHandler::PLAYBACK_ADDR_POOL[] = {
- CEC_ADDR_PLAYBACK_1,
- CEC_ADDR_PLAYBACK_2,
- CEC_ADDR_PLAYBACK_3
- };
-
- const cec_logical_address_t HdmiCecHandler::RECORDER_ADDR_POOL[] = {
- CEC_ADDR_RECORDER_1,
- CEC_ADDR_RECORDER_2,
- CEC_ADDR_RECORDER_3
- };
-
- const cec_logical_address_t HdmiCecHandler::TUNER_ADDR_POOL[] = {
- CEC_ADDR_TUNER_1,
- CEC_ADDR_TUNER_2,
- CEC_ADDR_TUNER_3,
- CEC_ADDR_TUNER_4
- };
-
-HdmiCecHandler::HdmiCecHandler(hdmi_cec_device_t* device, jobject callbacksObj) :
- mDevice(device),
- mCallbacksObj(callbacksObj) {
-}
-
-void HdmiCecHandler::initialize() {
- mDevice->register_event_callback(mDevice, HdmiCecHandler::onReceived, this);
- mMessageQueueHandler = new HdmiThread(this, true /* canCallJava */);
- mMessageQueueHandler->run("MessageHandler");
- updatePhysicalAddress();
-}
-
-uint16_t HdmiCecHandler::getPhysicalAddress() {
- return mPhysicalAddress;
-}
-
-cec_logical_address_t HdmiCecHandler::initLogicalDevice(cec_device_type_t type) {
- cec_logical_address addr = allocateLogicalAddress(type, CEC_ADDR_UNREGISTERED);
- if (addr != CEC_ADDR_UNREGISTERED && !mDevice->add_logical_address(mDevice, addr)) {
- mLogicalDevices.insert(std::pair<cec_device_type_t, cec_logical_address_t>(type, addr));
-
- // Broadcast <Report Physical Address> when a new logical address was allocated to let
- // other devices discover the new logical device and its logical - physical address
- // association.
- sendReportPhysicalAddress(addr);
- }
- return addr;
-}
-
-void HdmiCecHandler::releaseLogicalDevice(cec_device_type_t type) {
- std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.find(type);
- if (it != mLogicalDevices.end()) {
- mLogicalDevices.erase(it);
- }
- // TODO: remove the address monitored in HAL as well.
-}
-
-cec_logical_address_t HdmiCecHandler::getLogicalAddress(cec_device_type_t type) {
- std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.find(type);
- if (it != mLogicalDevices.end()) {
- return it->second;
- }
- return CEC_ADDR_UNREGISTERED;
-}
-
-cec_device_type_t HdmiCecHandler::getDeviceType(cec_logical_address_t addr) {
- std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin();
- for (; it != mLogicalDevices.end(); ++it) {
- if (it->second == addr) {
- return it->first;
- }
- }
- return CEC_DEVICE_INACTIVE;
-}
-
-void HdmiCecHandler::queueMessage(const MessageEntry& entry) {
- AutoMutex _l(mMessageQueueLock);
- if (mMessageQueue.size() <= MAX_BUFFER_SIZE) {
- mMessageQueue.push_back(entry);
- mMessageQueueCondition.signal();
- } else {
- ALOGW("Queue is full! Message dropped.");
- }
-}
-
-void HdmiCecHandler::queueOutgoingMessage(const cec_message_t& message) {
- queue_item_t item;
- item.cec = message;
- MessageEntry entry = std::make_pair(EVENT_TYPE_TX, item);
- queueMessage(entry);
-}
-
-void HdmiCecHandler::sendReportPhysicalAddress(cec_logical_address_t addr) {
- if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
- ALOGE("Invalid physical address.");
- return;
- }
- cec_device_type_t deviceType = getDeviceType(addr);
- if (deviceType == CEC_DEVICE_INACTIVE) {
- ALOGE("Invalid logical address: %d", addr);
- return;
- }
-
- cec_message_t msg;
- msg.initiator = addr;
- msg.destination = CEC_ADDR_BROADCAST;
- msg.length = 4;
- msg.body[0] = CEC_MESSAGE_REPORT_PHYSICAL_ADDRESS;
- msg.body[1] = (mPhysicalAddress >> 8) & 0xff;
- msg.body[2] = mPhysicalAddress & 0xff;
- msg.body[3] = deviceType;
- queueOutgoingMessage(msg);
-}
-
-void HdmiCecHandler::sendActiveSource(cec_logical_address_t srcAddr) {
- if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
- ALOGE("Error getting physical address.");
- return;
- }
- cec_message_t msg;
- msg.initiator = srcAddr;
- msg.destination = CEC_ADDR_BROADCAST;
- msg.length = 3;
- msg.body[0] = CEC_MESSAGE_ACTIVE_SOURCE;
- msg.body[1] = (mPhysicalAddress >> 8) & 0xff;
- msg.body[2] = mPhysicalAddress & 0xff;
- queueOutgoingMessage(msg);
-}
-
-void HdmiCecHandler::sendFeatureAbort(cec_logical_address_t srcAddr,
- cec_logical_address_t dstAddr, int opcode, int reason) {
- cec_message_t msg;
- msg.initiator = srcAddr;
- msg.destination = dstAddr;
- msg.length = 3;
- msg.body[0] = CEC_MESSAGE_FEATURE_ABORT;
- msg.body[1] = opcode;
- msg.body[2] = reason;
- queueOutgoingMessage(msg);
-}
-
-void HdmiCecHandler::sendCecVersion(cec_logical_address_t srcAddr,
- cec_logical_address_t dstAddr, int version) {
- cec_message_t msg;
- msg.initiator = srcAddr;
- msg.destination = dstAddr;
- msg.length = 2;
- msg.body[0] = CEC_MESSAGE_CEC_VERSION;
- msg.body[1] = version;
- queueOutgoingMessage(msg);
-}
-
-void HdmiCecHandler::sendGiveDeviceVendorID(cec_logical_address_t srcAddr,
- cec_logical_address_t dstAddr) {
- cec_message_t msg;
- msg.initiator = srcAddr;
- msg.destination = dstAddr;
- msg.length = 1;
- msg.body[0] = CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID;
- queueOutgoingMessage(msg);
-}
-
-void HdmiCecHandler::sendDeviceVendorId(cec_logical_address_t srcAddr,
- cec_logical_address_t dstAddr) {
- cec_message_t msg;
- msg.initiator = srcAddr;
- msg.destination = dstAddr;
- msg.length = 4;
- msg.body[0] = CEC_MESSAGE_DEVICE_VENDOR_ID;
- uint32_t vendor_id;
- mDevice->get_vendor_id(mDevice, &vendor_id);
- msg.body[1] = (vendor_id >> 16) & 0xff;
- msg.body[2] = (vendor_id >> 8) & 0xff;
- msg.body[3] = vendor_id & 0xff;
- queueOutgoingMessage(msg);
-}
-
-void HdmiCecHandler::sendSetOsdName(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
- const char* name, size_t len) {
- cec_message_t msg;
- msg.initiator = srcAddr;
- msg.destination = dstAddr;
- msg.body[0] = CEC_MESSAGE_SET_OSD_NAME;
- msg.length = min(len + 1, CEC_MESSAGE_BODY_MAX_LENGTH);
- std::memcpy(msg.body + 1, name, msg.length - 1);
- queueOutgoingMessage(msg);
-}
-
-void HdmiCecHandler::sendSetMenuLanguage(cec_logical_address_t srcAddr,
- cec_logical_address_t dstAddr) {
- char lang[4]; // buffer for 3-letter language code
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- jstring res = (jstring) env->CallObjectMethod(mCallbacksObj,
- gHdmiCecServiceClassInfo.getLanguage,
- getDeviceType(srcAddr));
- const char *clang = env->GetStringUTFChars(res, NULL);
- strlcpy(lang, clang, sizeof(lang));
- env->ReleaseStringUTFChars(res, clang);
-
- cec_message_t msg;
- msg.initiator = srcAddr;
- msg.destination = dstAddr;
- msg.length = 4; // opcode (1) + language code (3)
- msg.body[0] = CEC_MESSAGE_SET_MENU_LANGUAGE;
- std::memcpy(msg.body + 1, lang, 3);
- queueOutgoingMessage(msg);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-void HdmiCecHandler::sendCecMessage(const cec_message_t& message) {
- AutoMutex _l(mLock);
- ALOGV("sendCecMessage");
- mDevice->send_message(mDevice, &message);
-}
-
-void HdmiCecHandler::setOsdName(const char* name, size_t len) {
- mOsdName.assign(name, min(len, CEC_MESSAGE_BODY_MAX_LENGTH - 1));
-}
-
-// static
-void HdmiCecHandler::onReceived(const hdmi_event_t* event, void* arg) {
- HdmiCecHandler* handler = static_cast<HdmiCecHandler*>(arg);
- if (handler == NULL) {
- return;
- }
- queue_item_t item;
- if (event->type == HDMI_EVENT_CEC_MESSAGE) {
- item.cec = event->cec;
- MessageEntry entry = std::make_pair<int, const queue_item_t>(EVENT_TYPE_RX, item);
- handler->queueMessage(entry);
- } else if (event->type == HDMI_EVENT_HOT_PLUG) {
- item.hotplug = event->hotplug;
- MessageEntry entry = std::make_pair<int, const queue_item_t>(EVENT_TYPE_HOTPLUG, item);
- handler->queueMessage(entry);
- }
-}
-
-// static
-void HdmiCecHandler::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
- if (env->ExceptionCheck()) {
- ALOGE("An exception was thrown by callback '%s'.", methodName);
- LOGE_EX(env);
- env->ExceptionClear();
- }
-}
-
-void HdmiCecHandler::updatePhysicalAddress() {
- uint16_t addr;
- if (!mDevice->get_physical_address(mDevice, &addr)) {
- mPhysicalAddress = addr;
- } else {
- mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
- }
-}
-
-void HdmiCecHandler::updateLogicalAddress() {
- mDevice->clear_logical_address(mDevice);
- std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin();
- for (; it != mLogicalDevices.end(); ++it) {
- cec_logical_address_t addr;
- cec_logical_address_t preferredAddr = it->second;
- cec_device_type_t deviceType = it->first;
- addr = allocateLogicalAddress(deviceType, preferredAddr);
- if (!mDevice->add_logical_address(mDevice, addr)) {
- it->second = addr;
- } else {
- it->second = CEC_ADDR_UNREGISTERED;
- }
- }
-}
-
-cec_logical_address_t HdmiCecHandler::allocateLogicalAddress(cec_device_type_t type,
- cec_logical_address_t preferredAddr) {
- const cec_logical_address_t* addrPool;
- size_t poolSize;
- if (getLogicalAddressPool(type, &addrPool, &poolSize) < 0) {
- return CEC_ADDR_UNREGISTERED;
- }
- unsigned start = 0;
-
- // Find the index of preferred address in the pool. If not found, the start
- // position will be 0. This happens when the passed preferredAddr is set to
- // CEC_ADDR_UNREGISTERED, meaning that no preferred address is given.
- for (unsigned i = 0; i < poolSize; i++) {
- if (addrPool[i] == preferredAddr) {
- start = i;
- break;
- }
- }
- for (unsigned i = 0; i < poolSize; i++) {
- cec_logical_address_t addr = addrPool[(start + i) % poolSize];
- if (!sendPing(addr)) {
- // Failure in pinging means the address is available, not taken by any device.
- ALOGV("Logical Address Allocation success: %d", addr);
- return addr;
- }
- }
- ALOGE("Logical Address Allocation failed");
- return CEC_ADDR_UNREGISTERED;
-}
-
-bool HdmiCecHandler::sendPing(cec_logical_address addr) {
- cec_message_t msg;
- msg.initiator = msg.destination = addr;
- msg.length = 0;
- return !mDevice->send_message(mDevice, &msg);
-
-}
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-bool HdmiCecHandler::getLogicalAddressPool(cec_device_type_t deviceType,
- const cec_logical_address_t** addrPool, size_t* poolSize) {
- switch (deviceType) {
- case CEC_DEVICE_TV:
- *addrPool = TV_ADDR_POOL;
- *poolSize = ARRAY_SIZE(TV_ADDR_POOL);
- break;
- case CEC_DEVICE_RECORDER:
- *addrPool = RECORDER_ADDR_POOL;
- *poolSize = ARRAY_SIZE(RECORDER_ADDR_POOL);
- break;
- case CEC_DEVICE_TUNER:
- *addrPool = TUNER_ADDR_POOL;
- *poolSize = ARRAY_SIZE(TUNER_ADDR_POOL);
- break;
- case CEC_DEVICE_PLAYBACK:
- *addrPool = PLAYBACK_ADDR_POOL;
- *poolSize = ARRAY_SIZE(PLAYBACK_ADDR_POOL);
- break;
- default:
- ALOGE("Unsupported device type: %d", deviceType);
- return false;
- }
- return true;
-}
-
-#undef ARRAY_SIZE
-
-void HdmiCecHandler::dispatchMessage(const MessageEntry& entry) {
- int type = entry.first;
- mMessageQueueLock.unlock();
- if (type == EVENT_TYPE_RX) {
- mMessageQueue.pop_front();
- processIncomingMessage(entry.second.cec);
- } else if (type == EVENT_TYPE_TX) {
- sendCecMessage(entry.second.cec);
- mMessageQueue.pop_front();
- } else if (type == EVENT_TYPE_HOTPLUG) {
- mMessageQueue.pop_front();
- bool connected = entry.second.hotplug.connected;
- if (connected) {
- updatePhysicalAddress();
- updateLogicalAddress();
- }
- propagateHotplug(connected);
- }
- mMessageQueueLock.lock();
-}
-
-void HdmiCecHandler::processIncomingMessage(const cec_message_t& msg) {
- int opcode = msg.body[0];
- if (opcode == CEC_MESSAGE_GIVE_PHYSICAL_ADDRESS) {
- sendReportPhysicalAddress(msg.destination);
- } else if (opcode == CEC_MESSAGE_REQUEST_ACTIVE_SOURCE) {
- handleRequestActiveSource();
- } else if (opcode == CEC_MESSAGE_GIVE_OSD_NAME) {
- handleGiveOsdName(msg);
- } else if (opcode == CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID) {
- handleGiveDeviceVendorID(msg);
- } else if (opcode == CEC_MESSAGE_GET_CEC_VERSION) {
- handleGetCECVersion(msg);
- } else if (opcode == CEC_MESSAGE_GET_MENU_LANGUAGE) {
- handleGetMenuLanguage(msg);
- } else if (opcode == CEC_MESSAGE_ABORT) {
- // Compliance testing requires that abort message be responded with feature abort.
- sendFeatureAbort(msg.destination, msg.initiator, msg.body[0], ABORT_REFUSED);
- } else {
- if (precheckMessage(msg)) {
- propagateMessage(msg);
- }
- }
-}
-
-bool HdmiCecHandler::precheckMessage(const cec_message_t& msg) {
- // Check if this is the broadcast message coming to itself, which need not be passed
- // back to framework. This happens because CEC spec specifies that a physical device
- // may host multiple logical devices. A broadcast message sent by one of them therefore
- // should be able to reach the others by the loopback mechanism.
- //
- // Currently we don't deal with multiple logical devices, so this is not necessary.
- // It should be revisited once we support hosting multiple logical devices.
- int opcode = msg.body[0];
- if (msg.destination == CEC_ADDR_BROADCAST &&
- (opcode == CEC_MESSAGE_ACTIVE_SOURCE ||
- opcode == CEC_MESSAGE_SET_STREAM_PATH ||
- opcode == CEC_MESSAGE_INACTIVE_SOURCE)) {
- uint16_t senderAddr = (msg.body[1] << 8) + msg.body[2];
- if (senderAddr == mPhysicalAddress) {
- return false;
- }
- }
- return true;
-}
-
-void HdmiCecHandler::propagateMessage(const cec_message_t& msg) {
- int paramLen = msg.length - 1;
- jint srcAddr = msg.initiator;
- jint dstAddr = msg.destination;
- jint opcode = msg.body[0];
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- jbyteArray params = env->NewByteArray(paramLen);
- const jbyte* body = reinterpret_cast<const jbyte *>(msg.body + 1);
- if (paramLen > 0) {
- env->SetByteArrayRegion(params, 0, paramLen, body);
- }
- env->CallVoidMethod(mCallbacksObj,
- gHdmiCecServiceClassInfo.handleMessage,
- srcAddr, dstAddr, opcode, params);
- env->DeleteLocalRef(params);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-void HdmiCecHandler::propagateHotplug(bool connected) {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(mCallbacksObj,
- gHdmiCecServiceClassInfo.handleHotplug,
- connected);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-
-void HdmiCecHandler::handleRequestActiveSource() {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- jint activeDeviceType = env->CallIntMethod(mCallbacksObj,
- gHdmiCecServiceClassInfo.getActiveSource);
- if (activeDeviceType != CEC_DEVICE_INACTIVE) {
- sendActiveSource(getLogicalAddress(static_cast<cec_device_type_t>(activeDeviceType)));
- }
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-void HdmiCecHandler::handleGiveOsdName(const cec_message_t& msg) {
- if (!mOsdName.empty()) {
- sendSetOsdName(msg.destination, msg.initiator, mOsdName.c_str(), mOsdName.length());
- }
-}
-
-void HdmiCecHandler::handleGiveDeviceVendorID(const cec_message_t& msg) {
- sendDeviceVendorId(msg.destination, msg.initiator);
-}
-
-void HdmiCecHandler::handleGetCECVersion(const cec_message_t& msg) {
- int version;
- mDevice->get_version(mDevice, &version);
- sendCecVersion(msg.destination, msg.initiator, version);
-}
-
-void HdmiCecHandler::handleGetMenuLanguage(const cec_message_t& msg) {
- sendSetMenuLanguage(msg.destination, msg.initiator);
-}
-
-//------------------------------------------------------------------------------
-
-#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
- var = env->GetMethodID(clazz, methodName, methodDescriptor); \
- LOG_FATAL_IF(! var, "Unable to find method " methodName);
-
-static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj) {
- int err;
- hw_module_t* module;
- err = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID, const_cast<const hw_module_t **>(&module));
- if (err != 0) {
- ALOGE("Error acquiring hardware module: %d", err);
- return 0;
- }
- hw_device_t* device;
- err = module->methods->open(module, HDMI_CEC_HARDWARE_INTERFACE, &device);
- if (err != 0) {
- ALOGE("Error opening hardware module: %d", err);
- return 0;
- }
- HdmiCecHandler *handler = new HdmiCecHandler(reinterpret_cast<hdmi_cec_device *>(device),
- env->NewGlobalRef(callbacksObj));
- handler->initialize();
-
- GET_METHOD_ID(gHdmiCecServiceClassInfo.handleMessage, clazz,
- "handleMessage", "(III[B)V");
- GET_METHOD_ID(gHdmiCecServiceClassInfo.handleHotplug, clazz,
- "handleHotplug", "(Z)V");
- GET_METHOD_ID(gHdmiCecServiceClassInfo.getActiveSource, clazz,
- "getActiveSource", "()I");
- GET_METHOD_ID(gHdmiCecServiceClassInfo.getLanguage, clazz,
- "getLanguage", "(I)Ljava/lang/String;");
-
- return reinterpret_cast<jlong>(handler);
-}
-
-static void nativeSendMessage(JNIEnv* env, jclass clazz, jlong handlerPtr, jint deviceType,
- jint dstAddr, jint opcode, jbyteArray params) {
- HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
- cec_logical_address_t srcAddr = handler->getLogicalAddress(
- static_cast<cec_device_type_t>(deviceType));
- jsize len = env->GetArrayLength(params);
- ScopedByteArrayRO paramsPtr(env, params);
- cec_message_t message;
- message.initiator = srcAddr;
- message.destination = static_cast<cec_logical_address_t>(dstAddr);
- message.length = min(len + 1, CEC_MESSAGE_BODY_MAX_LENGTH);
- message.body[0] = opcode;
- std::memcpy(message.body + 1, paramsPtr.get(), message.length - 1);
- handler->sendCecMessage(message);
-}
-
-static jint nativeAllocateLogicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr,
- jint deviceType) {
- HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
- return handler->initLogicalDevice(static_cast<cec_device_type_t>(deviceType));
-}
-
-static void nativeRemoveLogicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr,
- jint deviceType) {
- HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
- return handler->releaseLogicalDevice(static_cast<cec_device_type_t>(deviceType));
-}
-
-static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr) {
- HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
- return handler->getPhysicalAddress();
-}
-
-static void nativeSetOsdName(JNIEnv* env, jclass clazz, jlong handlerPtr, jbyteArray name) {
- HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
- jsize len = env->GetArrayLength(name);
- if (len > 0) {
- ScopedByteArrayRO namePtr(env, name);
- handler->setOsdName(reinterpret_cast<const char *>(namePtr.get()), len);
- }
-}
-
-static JNINativeMethod sMethods[] = {
- /* name, signature, funcPtr */
- { "nativeInit", "(Lcom/android/server/hdmi/HdmiCecService;)J",
- (void *)nativeInit },
- { "nativeSendMessage", "(JIII[B)V",
- (void *)nativeSendMessage },
- { "nativeAllocateLogicalAddress", "(JI)I",
- (void *)nativeAllocateLogicalAddress },
- { "nativeRemoveLogicalAddress", "(JI)V",
- (void *)nativeRemoveLogicalAddress },
- { "nativeGetPhysicalAddress", "(J)I",
- (void *)nativeGetPhysicalAddress },
- { "nativeSetOsdName", "(J[B)V",
- (void *)nativeSetOsdName },
-};
-
-#define CLASS_PATH "com/android/server/hdmi/HdmiCecService"
-
-int register_android_server_hdmi_HdmiCecService(JNIEnv* env) {
- int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods));
- LOG_FATAL_IF(res < 0, "Unable to register native methods.");
- return 0;
-}
-
-} /* namespace android */
diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
index e9ba116..5bafb52 100644
--- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -30,6 +30,8 @@
#include <string.h>
#include <pthread.h>
+#include <linux/in.h>
+#include <linux/in6.h>
static jobject mCallbacksObj = NULL;
@@ -168,19 +170,98 @@
create_thread_callback,
};
+static jbyteArray convert_to_ipv4(uint32_t ip, bool net_order)
+{
+ if (INADDR_NONE == ip) {
+ return NULL;
+ }
+
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jbyteArray byteArray = env->NewByteArray(4);
+ if (byteArray == NULL) {
+ ALOGE("Unable to allocate byte array for IPv4 address");
+ return NULL;
+ }
+
+ jbyte ipv4[4];
+ if (net_order) {
+ memcpy(ipv4, &ip, sizeof(ipv4));
+ } else {
+ //endianess transparent conversion from int to char[]
+ ipv4[0] = (jbyte) (ip & 0xFF);
+ ipv4[1] = (jbyte)((ip>>8) & 0xFF);
+ ipv4[2] = (jbyte)((ip>>16) & 0xFF);
+ ipv4[3] = (jbyte) (ip>>24);
+ }
+
+ env->SetByteArrayRegion(byteArray, 0, 4, (const jbyte*) ipv4);
+ return byteArray;
+}
+
static void agps_status_callback(AGpsStatus* agps_status)
{
JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jbyteArray byteArray = NULL;
+ bool isSupported = false;
- uint32_t ipaddr;
- // ipaddr field was not included in original AGpsStatus
- if (agps_status->size >= sizeof(AGpsStatus))
- ipaddr = agps_status->ipaddr;
- else
- ipaddr = 0xFFFFFFFF;
- env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus,
- agps_status->type, agps_status->status, ipaddr);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ size_t status_size = agps_status->size;
+ if (status_size == sizeof(AGpsStatus_v3)) {
+ switch (agps_status->addr.ss_family)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in *in = (struct sockaddr_in*)&(agps_status->addr);
+ uint32_t *pAddr = (uint32_t*)&(in->sin_addr);
+ byteArray = convert_to_ipv4(*pAddr, true /* net_order */);
+ if (byteArray != NULL) {
+ isSupported = true;
+ }
+ }
+ break;
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(agps_status->addr);
+ byteArray = env->NewByteArray(16);
+ if (byteArray != NULL) {
+ env->SetByteArrayRegion(byteArray, 0, 16, (const jbyte *)&(in6->sin6_addr));
+ isSupported = true;
+ } else {
+ ALOGE("Unable to allocate byte array for IPv6 address.");
+ }
+ }
+ break;
+ default:
+ ALOGE("Invalid ss_family found: %d", agps_status->addr.ss_family);
+ break;
+ }
+ } else if (status_size >= sizeof(AGpsStatus_v2)) {
+ // for back-compatibility reasons we check in v2 that the data structure size is greater or
+ // equal to the declared size in gps.h
+ uint32_t ipaddr = agps_status->ipaddr;
+ byteArray = convert_to_ipv4(ipaddr, false /* net_order */);
+ if (ipaddr == INADDR_NONE || byteArray != NULL) {
+ isSupported = true;
+ }
+ } else if (status_size >= sizeof(AGpsStatus_v1)) {
+ // because we have to check for >= with regards to v2, we also need to relax the check here
+ // and only make sure that the size is at least what we expect
+ isSupported = true;
+ } else {
+ ALOGE("Invalid size of AGpsStatus found: %d.", status_size);
+ }
+
+ if (isSupported) {
+ env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus, agps_status->type,
+ agps_status->status, byteArray);
+
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ } else {
+ ALOGD("Skipping calling method_reportAGpsStatus.");
+ }
+
+ if (byteArray) {
+ env->DeleteLocalRef(byteArray);
+ }
}
AGpsCallbacks sAGpsCallbacks = {
@@ -339,7 +420,7 @@
method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
- method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(III)V");
+ method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
@@ -610,7 +691,8 @@
env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
}
-static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn)
+static void android_location_GpsLocationProvider_agps_data_conn_open(
+ JNIEnv* env, jobject obj, jstring apn, jint apnIpType)
{
if (!sAGpsInterface) {
ALOGE("no AGPS interface in agps_data_conn_open");
@@ -620,8 +702,18 @@
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
+
const char *apnStr = env->GetStringUTFChars(apn, NULL);
- sAGpsInterface->data_conn_open(apnStr);
+
+ size_t interface_size = sAGpsInterface->size;
+ if (interface_size == sizeof(AGpsInterface_v2)) {
+ sAGpsInterface->data_conn_open_with_apn_ip_type(apnStr, apnIpType);
+ } else if (interface_size == sizeof(AGpsInterface_v1)) {
+ sAGpsInterface->data_conn_open(apnStr);
+ } else {
+ ALOGE("Invalid size of AGpsInterface found: %d.", interface_size);
+ }
+
env->ReleaseStringUTFChars(apn, apnStr);
}
@@ -775,7 +867,7 @@
{"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location},
{"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
{"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data},
- {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open},
+ {"native_agps_data_conn_open", "(Ljava/lang/String;I)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open},
{"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
{"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
{"native_agps_set_id","(ILjava/lang/String;)V",(void*)android_location_GpsLocationProvider_agps_set_id},
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index bfa8286..a302104 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -39,7 +39,6 @@
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_dreams_McuHal(JNIEnv* env);
int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
-int register_android_server_hdmi_HdmiCecService(JNIEnv* env);
int register_android_server_hdmi_HdmiMhlController(JNIEnv* env);
int register_android_server_tv_TvInputHal(JNIEnv* env);
};
@@ -76,8 +75,6 @@
register_android_server_dreams_McuHal(env);
register_android_server_BatteryStatsService(env);
register_android_server_hdmi_HdmiCecController(env);
- // TODO: remove this once replaces HdmiCecService with HdmiControlService.
- register_android_server_hdmi_HdmiCecService(env);
register_android_server_hdmi_HdmiMhlController(env);
register_android_server_tv_TvInputHal(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 674c6f4..f1284d80 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -120,6 +120,10 @@
mDeviceOwner = new OwnerInfo(ownerName, packageName);
}
+ void clearDeviceOwner() {
+ mDeviceOwner = null;
+ }
+
void setProfileOwner(String packageName, String ownerName, int userId) {
mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName));
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a0b75b5..4574caf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -32,6 +32,7 @@
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AppGlobals;
+import android.app.IActivityManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -51,6 +52,10 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
+import android.media.AudioManager;
+import android.media.IAudioService;
+import android.net.ConnectivityManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ProxyInfo;
import android.os.Binder;
import android.os.Bundle;
@@ -814,12 +819,20 @@
}
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_PROFILE_OWNER) {
+ throw new SecurityException("Admin " + candidates.get(0).info.getComponent()
+ + " does not own the profile");
+ }
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);
+ + Binder.getCallingUid() + " for policy #" + reqPolicy);
}
}
@@ -827,15 +840,23 @@
sendAdminCommandLocked(admin, action, null);
}
+ void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
+ sendAdminCommandLocked(admin, action, null, result);
+ }
+
/**
* Send an update to one specific admin, get notified when that admin returns a result.
*/
- void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
+ void sendAdminCommandLocked(ActiveAdmin admin, String action, Bundle adminExtras,
+ BroadcastReceiver result) {
Intent intent = new Intent(action);
intent.setComponent(admin.info.getComponent());
if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
intent.putExtra("expiration", admin.passwordExpirationDate);
}
+ if (adminExtras != null) {
+ intent.putExtras(adminExtras);
+ }
if (result != null) {
mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
null, result, mHandler, Activity.RESULT_OK, null, null);
@@ -1363,6 +1384,11 @@
if (!mHasFeature) {
return;
}
+ setActiveAdmin(adminReceiver, refreshing, userHandle, null);
+ }
+
+ private void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle,
+ Bundle onEnableData) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
enforceCrossUserPermission(userHandle);
@@ -1399,7 +1425,8 @@
policy.mAdminList.set(replaceIndex, newAdmin);
}
saveSettingsLocked(userHandle);
- sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
+ sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
+ onEnableData, null);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2722,6 +2749,20 @@
return null;
}
+ public void setRecommendedGlobalProxy(ComponentName who, ProxyInfo proxyInfo) {
+ synchronized (this) {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ }
+ long token = Binder.clearCallingIdentity();
+ try {
+ ConnectivityManager connectivityManager = (ConnectivityManager)
+ mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ connectivityManager.setGlobalProxy(proxyInfo);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private void resetGlobalProxyLocked(DevicePolicyData policy) {
final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
@@ -3083,6 +3124,37 @@
}
@Override
+ public void clearDeviceOwner(String packageName) {
+ if (packageName == null) {
+ throw new NullPointerException("packageName is null");
+ }
+ try {
+ int uid = mContext.getPackageManager().getPackageUid(packageName, 0);
+ if (uid != Binder.getCallingUid()) {
+ throw new SecurityException("Invalid packageName");
+ }
+ } catch (NameNotFoundException e) {
+ throw new SecurityException(e);
+ }
+ if (!isDeviceOwner(packageName)) {
+ throw new SecurityException("clearDeviceOwner can only be called by the device owner");
+ }
+ synchronized (this) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mUserManager.setUserRestrictions(new Bundle(),
+ new UserHandle(UserHandle.USER_OWNER));
+ if (mDeviceOwner != null) {
+ mDeviceOwner.clearDeviceOwner();
+ mDeviceOwner.writeOwnerFile();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @Override
public boolean setProfileOwner(String packageName, String ownerName, int userHandle) {
if (!mHasFeature) {
return false;
@@ -3441,6 +3513,36 @@
}
@Override
+ public UserHandle createAndInitializeUser(ComponentName who, String name,
+ String ownerName, ComponentName profileOwnerComponent, Bundle adminExtras) {
+ UserHandle user = createUser(who, name);
+ long id = Binder.clearCallingIdentity();
+ try {
+ String profileOwnerPkg = profileOwnerComponent.getPackageName();
+ final IPackageManager ipm = AppGlobals.getPackageManager();
+ IActivityManager activityManager = ActivityManagerNative.getDefault();
+
+ try {
+ // Install the profile owner if not present.
+ if (!ipm.isPackageAvailable(profileOwnerPkg, user.getIdentifier())) {
+ ipm.installExistingPackageAsUser(profileOwnerPkg, user.getIdentifier());
+ }
+
+ // Start user in background.
+ activityManager.startUserInBackground(user.getIdentifier());
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Failed to make remote calls for configureUser", e);
+ }
+
+ setActiveAdmin(profileOwnerComponent, true, user.getIdentifier(), adminExtras);
+ setProfileOwner(profileOwnerPkg, ownerName, user.getIdentifier());
+ return user;
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+
+ @Override
public boolean removeUser(ComponentName who, UserHandle userHandle) {
synchronized (this) {
if (who == null) {
@@ -3728,4 +3830,40 @@
}
}
}
+
+ @Override
+ public void setMasterVolumeMuted(ComponentName who, boolean on) {
+ final ContentResolver contentResolver = mContext.getContentResolver();
+
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ IAudioService iAudioService = IAudioService.Stub.asInterface(
+ ServiceManager.getService(Context.AUDIO_SERVICE));
+ try{
+ iAudioService.setMasterMute(on, 0, who.getPackageName(), null);
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Failed to setMasterMute", re);
+ }
+ }
+ }
+
+ @Override
+ public boolean isMasterVolumeMuted(ComponentName who) {
+ final ContentResolver contentResolver = mContext.getContentResolver();
+
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ AudioManager audioManager =
+ (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ return audioManager.isMasterMute();
+ }
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 18ece5b..f946595 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -44,6 +44,7 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.service.dreams.DreamService;
+import android.service.fingerprint.FingerprintManager;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -63,8 +64,10 @@
import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
+import com.android.server.fingerprint.FingerprintService;
import com.android.server.hdmi.HdmiControlService;
import com.android.server.input.InputManagerService;
+import com.android.server.job.JobSchedulerService;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LightsService;
import com.android.server.media.MediaRouterService;
@@ -84,7 +87,6 @@
import com.android.server.search.SearchManagerService;
import com.android.server.statusbar.StatusBarManagerService;
import com.android.server.storage.DeviceStorageMonitorService;
-import com.android.server.task.TaskManagerService;
import com.android.server.trust.TrustManagerService;
import com.android.server.tv.TvInputManagerService;
import com.android.server.twilight.TwilightService;
@@ -130,12 +132,10 @@
"com.android.server.wifi.passpoint.WifiPasspointService";
private static final String WIFI_P2P_SERVICE_CLASS =
"com.android.server.wifi.p2p.WifiP2pService";
- private static final String HDMI_CEC_SERVICE_CLASS =
- "com.android.server.hdmi.HdmiCecService";
private static final String ETHERNET_SERVICE_CLASS =
"com.android.server.ethernet.EthernetService";
- private static final String TASK_SERVICE_CLASS =
- "com.android.server.task.TaskManagerService";
+ private static final String JOB_SCHEDULER_SERVICE_CLASS =
+ "com.android.server.job.JobSchedulerService";
private final int mFactoryTestMode;
private Timer mProfilerSnapshotTimer;
@@ -351,6 +351,7 @@
boolean disableSystemUI = SystemProperties.getBoolean("config.disable_systemui", false);
boolean disableNonCoreServices = SystemProperties.getBoolean("config.disable_noncore", false);
boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false);
+ boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
try {
Slog.i(TAG, "Telephony Registry");
@@ -463,7 +464,7 @@
// Skip Bluetooth if we have an emulator kernel
// TODO: Use a more reliable check to see if this product should
// support Bluetooth - see bug 988521
- if (SystemProperties.get("ro.kernel.qemu").equals("1")) {
+ if (isEmulator) {
Slog.i(TAG, "No Bluetooh Service (emulator)");
} else if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
Slog.i(TAG, "No Bluetooth Service (factory test)");
@@ -664,10 +665,17 @@
reportWtf("starting Wi-Fi Scanning Service", e);
}
- try {
- mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
- } catch (Throwable e) {
- reportWtf("starting Ethernet Service", e);
+ if (!isEmulator) {
+ try {
+ mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
+ } catch (Throwable e) {
+ reportWtf("starting Ethernet Service", e);
+ }
+ } else {
+ // Don't start the Ethernet service on the emulator because
+ // it interferes with qemu's SLIRP emulation, which uses
+ // IPv4 over eth0. http://b/15341003 .
+ Slog.i(TAG, "Not starting Ethernet service (emulator)");
}
try {
@@ -828,7 +836,7 @@
mSystemServiceManager.startService(UiModeManagerService.class);
- mSystemServiceManager.startService(TaskManagerService.class);
+ mSystemServiceManager.startService(JobSchedulerService.class);
if (!disableNonCoreServices) {
try {
@@ -927,13 +935,6 @@
}
try {
- Slog.i(TAG, "IdleMaintenanceService");
- new IdleMaintenanceService(context, battery);
- } catch (Throwable e) {
- reportWtf("starting IdleMaintenanceService", e);
- }
-
- try {
if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
}
@@ -954,12 +955,6 @@
}
try {
- mSystemServiceManager.startService(HDMI_CEC_SERVICE_CLASS);
- } catch (Throwable e) {
- reportWtf("starting HdmiCec Service", e);
- }
-
- try {
mSystemServiceManager.startService(HdmiControlService.class);
} catch (Throwable e) {
reportWtf("starting HdmiControlService", e);
@@ -989,11 +984,19 @@
}
try {
+ Slog.i(TAG, "Fingerprint Manager");
+ mSystemServiceManager.startService(FingerprintService.class);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting FingerprintService", e);
+ }
+
+ try {
Slog.i(TAG, "BackgroundDexOptService");
- new BackgroundDexOptService(context);
+ BackgroundDexOptService.schedule(context);
} catch (Throwable e) {
reportWtf("starting BackgroundDexOptService", e);
}
+
}
try {
diff --git a/services/print/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java
index 1bb61d2..a8c739c 100644
--- a/services/print/java/com/android/server/print/RemotePrintService.java
+++ b/services/print/java/com/android/server/print/RemotePrintService.java
@@ -121,15 +121,7 @@
throwIfDestroyed();
// Stop tracking printers.
- if (mTrackedPrinterList != null) {
- final int trackedPrinterCount = mTrackedPrinterList.size();
- for (int i = 0; i < trackedPrinterCount; i++) {
- PrinterId printerId = mTrackedPrinterList.get(i);
- if (printerId.getServiceName().equals(mComponentName)) {
- handleStopPrinterStateTracking(printerId);
- }
- }
- }
+ stopTrackingAllPrinters();
// Stop printer discovery.
if (mDiscoveryPriorityList != null) {
@@ -270,7 +262,7 @@
try {
mPrintService.createPrinterDiscoverySession();
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error creating printer dicovery session.", re);
+ Slog.e(LOG_TAG, "Error creating printer discovery session.", re);
}
}
}
@@ -365,10 +357,14 @@
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterDiscovery()");
}
+
+ // Stop tracking printers.
+ stopTrackingAllPrinters();
+
try {
mPrintService.stopPrinterDiscovery();
} catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error stopping printer dicovery.", re);
+ Slog.e(LOG_TAG, "Error stopping printer discovery.", re);
}
}
}
@@ -466,6 +462,19 @@
}
}
+ private void stopTrackingAllPrinters() {
+ if (mTrackedPrinterList == null) {
+ return;
+ }
+ final int trackedPrinterCount = mTrackedPrinterList.size();
+ for (int i = trackedPrinterCount - 1; i >= 0; i--) {
+ PrinterId printerId = mTrackedPrinterList.get(i);
+ if (printerId.getServiceName().equals(mComponentName)) {
+ handleStopPrinterStateTracking(printerId);
+ }
+ }
+ }
+
public void dump(PrintWriter pw, String prefix) {
String tab = " ";
pw.append(prefix).append("service:").println();
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index ffe9806..9496cae 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -44,7 +44,7 @@
/**
* This represents the remote print spooler as a local object to the
- * PrintManagerSerivce. It is responsible to connecting to the remote
+ * PrintManagerService. It is responsible to connecting to the remote
* spooler if needed, to make the timed remote calls, to handle
* remote exceptions, and to bind/unbind to the remote instance as
* needed.
@@ -99,7 +99,7 @@
mClient = new PrintSpoolerClient(this);
mIntent = new Intent();
mIntent.setComponent(new ComponentName("com.android.printspooler",
- "com.android.printspooler.PrintSpoolerService"));
+ "com.android.printspooler.model.PrintSpoolerService"));
}
public final List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, int state,
diff --git a/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java b/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java
index e7f9ca0..7a7fa07 100644
--- a/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/task/TaskStoreTest.java
@@ -3,18 +3,19 @@
import android.content.ComponentName;
import android.content.Context;
-import android.app.task.Task;
-import android.app.task.Task.Builder;
+import android.app.job.JobInfo;
+import android.app.job.JobInfo.Builder;
import android.os.PersistableBundle;
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import android.util.Log;
-import com.android.server.task.controllers.TaskStatus;
+import com.android.server.job.JobMapReadFinishedListener;
+import com.android.server.job.JobStore;
+import com.android.server.job.controllers.JobStatus;
import java.util.List;
-import static com.android.server.task.TaskStore.initAndGet;
/**
* Test reading and writing correctly from file.
*/
@@ -26,12 +27,12 @@
private ComponentName mComponent;
private static final long IO_WAIT = 600L;
- TaskStore mTaskStoreUnderTest;
+ JobStore mTaskStoreUnderTest;
Context mTestContext;
- TaskMapReadFinishedListener mTaskMapReadFinishedListenerStub =
- new TaskMapReadFinishedListener() {
+ JobMapReadFinishedListener mTaskMapReadFinishedListenerStub =
+ new JobMapReadFinishedListener() {
@Override
- public void onTaskMapReadFinished(List<TaskStatus> tasks) {
+ public void onJobMapReadFinished(List<JobStatus> tasks) {
// do nothing.
}
};
@@ -40,7 +41,7 @@
public void setUp() throws Exception {
mTestContext = new RenamingDelegatingContext(getContext(), TEST_PREFIX);
Log.d(TAG, "Saving tasks to '" + mTestContext.getFilesDir() + "'");
- mTaskStoreUnderTest = TaskStore.initAndGetForTesting(mTestContext,
+ mTaskStoreUnderTest = JobStore.initAndGetForTesting(mTestContext,
mTestContext.getFilesDir(), mTaskMapReadFinishedListenerStub);
mComponent = new ComponentName(getContext().getPackageName(), StubClass.class.getName());
}
@@ -56,23 +57,23 @@
long runFromMillis = 2000L; // 2s
long initialBackoff = 10000L; // 10s
- final Task task = new Builder(taskId, mComponent)
+ final JobInfo task = new Builder(taskId, mComponent)
.setRequiresCharging(true)
- .setRequiredNetworkCapabilities(Task.NetworkType.ANY)
- .setBackoffCriteria(initialBackoff, Task.BackoffPolicy.EXPONENTIAL)
+ .setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY)
+ .setBackoffCriteria(initialBackoff, JobInfo.BackoffPolicy.EXPONENTIAL)
.setOverrideDeadline(runByMillis)
.setMinimumLatency(runFromMillis)
.build();
- final TaskStatus ts = new TaskStatus(task, SOME_UID, true /* persisted */);
+ final JobStatus ts = new JobStatus(task, SOME_UID, true /* persisted */);
mTaskStoreUnderTest.add(ts);
Thread.sleep(IO_WAIT);
// Manually load tasks from xml file.
- mTaskStoreUnderTest.readTaskMapFromDisk(new TaskMapReadFinishedListener() {
+ mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() {
@Override
- public void onTaskMapReadFinished(List<TaskStatus> tasks) {
+ public void onJobMapReadFinished(List<JobStatus> tasks) {
assertEquals("Didn't get expected number of persisted tasks.", 1, tasks.size());
- TaskStatus loadedTaskStatus = tasks.get(0);
- assertTasksEqual(task, loadedTaskStatus.getTask());
+ JobStatus loadedTaskStatus = tasks.get(0);
+ assertTasksEqual(task, loadedTaskStatus.getJob());
assertEquals("Different uids.", SOME_UID, tasks.get(0).getUid());
compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
ts.getEarliestRunTime(), loadedTaskStatus.getEarliestRunTime());
@@ -84,30 +85,30 @@
}
public void testWritingTwoFilesToDisk() throws Exception {
- final Task task1 = new Builder(8, mComponent)
+ final JobInfo task1 = new Builder(8, mComponent)
.setRequiresDeviceIdle(true)
.setPeriodic(10000L)
.setRequiresCharging(true)
.build();
- final Task task2 = new Builder(12, mComponent)
+ final JobInfo task2 = new Builder(12, mComponent)
.setMinimumLatency(5000L)
- .setBackoffCriteria(15000L, Task.BackoffPolicy.LINEAR)
+ .setBackoffCriteria(15000L, JobInfo.BackoffPolicy.LINEAR)
.setOverrideDeadline(30000L)
- .setRequiredNetworkCapabilities(Task.NetworkType.UNMETERED)
+ .setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED)
.build();
- final TaskStatus taskStatus1 = new TaskStatus(task1, SOME_UID, true /* persisted */);
- final TaskStatus taskStatus2 = new TaskStatus(task2, SOME_UID, true /* persisted */);
+ final JobStatus taskStatus1 = new JobStatus(task1, SOME_UID, true /* persisted */);
+ final JobStatus taskStatus2 = new JobStatus(task2, SOME_UID, true /* persisted */);
mTaskStoreUnderTest.add(taskStatus1);
mTaskStoreUnderTest.add(taskStatus2);
Thread.sleep(IO_WAIT);
- mTaskStoreUnderTest.readTaskMapFromDisk(new TaskMapReadFinishedListener() {
+ mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() {
@Override
- public void onTaskMapReadFinished(List<TaskStatus> tasks) {
+ public void onJobMapReadFinished(List<JobStatus> tasks) {
assertEquals("Incorrect # of persisted tasks.", 2, tasks.size());
- TaskStatus loaded1 = tasks.get(0);
- TaskStatus loaded2 = tasks.get(1);
- assertTasksEqual(task1, loaded1.getTask());
- assertTasksEqual(task2, loaded2.getTask());
+ JobStatus loaded1 = tasks.get(0);
+ JobStatus loaded2 = tasks.get(1);
+ assertTasksEqual(task1, loaded1.getJob());
+ assertTasksEqual(task2, loaded2.getJob());
// Check that the loaded task has the correct runtimes.
compareTimestampsSubjectToIoLatency("Early run-times not the same after read.",
@@ -124,7 +125,7 @@
}
public void testWritingTaskWithExtras() throws Exception {
- Task.Builder b = new Builder(8, mComponent)
+ JobInfo.Builder b = new Builder(8, mComponent)
.setRequiresDeviceIdle(true)
.setPeriodic(10000L)
.setRequiresCharging(true);
@@ -134,17 +135,17 @@
extras.putString("hi", "there");
extras.putInt("into", 3);
b.setExtras(extras);
- final Task task = b.build();
- TaskStatus taskStatus = new TaskStatus(task, SOME_UID, true /* persisted */);
+ final JobInfo task = b.build();
+ JobStatus taskStatus = new JobStatus(task, SOME_UID, true /* persisted */);
mTaskStoreUnderTest.add(taskStatus);
Thread.sleep(IO_WAIT);
- mTaskStoreUnderTest.readTaskMapFromDisk(new TaskMapReadFinishedListener() {
+ mTaskStoreUnderTest.readJobMapFromDisk(new JobMapReadFinishedListener() {
@Override
- public void onTaskMapReadFinished(List<TaskStatus> tasks) {
+ public void onJobMapReadFinished(List<JobStatus> tasks) {
assertEquals("Incorrect # of persisted tasks.", 1, tasks.size());
- TaskStatus loaded = tasks.get(0);
- assertTasksEqual(task, loaded.getTask());
+ JobStatus loaded = tasks.get(0);
+ assertTasksEqual(task, loaded.getJob());
}
});
@@ -153,7 +154,7 @@
/**
* Helper function to throw an error if the provided task and TaskStatus objects are not equal.
*/
- private void assertTasksEqual(Task first, Task second) {
+ private void assertTasksEqual(JobInfo first, JobInfo second) {
assertEquals("Different task ids.", first.getId(), second.getId());
assertEquals("Different components.", first.getService(), second.getService());
assertEquals("Different periodic status.", first.isPeriodic(), second.isPeriodic());
@@ -168,11 +169,11 @@
assertEquals("Invalid idle constraint.", first.isRequireDeviceIdle(),
second.isRequireDeviceIdle());
assertEquals("Invalid unmetered constraint.",
- first.getNetworkCapabilities() == Task.NetworkType.UNMETERED,
- second.getNetworkCapabilities() == Task.NetworkType.UNMETERED);
+ first.getNetworkCapabilities() == JobInfo.NetworkType.UNMETERED,
+ second.getNetworkCapabilities() == JobInfo.NetworkType.UNMETERED);
assertEquals("Invalid connectivity constraint.",
- first.getNetworkCapabilities() == Task.NetworkType.ANY,
- second.getNetworkCapabilities() == Task.NetworkType.ANY);
+ first.getNetworkCapabilities() == JobInfo.NetworkType.ANY,
+ second.getNetworkCapabilities() == JobInfo.NetworkType.ANY);
assertEquals("Invalid deadline constraint.",
first.hasLateConstraint(),
second.hasLateConstraint());
diff --git a/services/tests/servicestests/src/com/android/server/task/controllers/BatteryControllerTest.java b/services/tests/servicestests/src/com/android/server/task/controllers/BatteryControllerTest.java
deleted file mode 100644
index e617caf..0000000
--- a/services/tests/servicestests/src/com/android/server/task/controllers/BatteryControllerTest.java
+++ /dev/null
@@ -1,66 +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.server.task.controllers;
-
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.test.AndroidTestCase;
-
-import com.android.server.task.StateChangedListener;
-
-import static com.android.server.task.controllers.BatteryController.getForTesting;
-
-import static org.mockito.Mockito.*;
-
-/**
- *
- */
-public class BatteryControllerTest extends AndroidTestCase {
- BatteryController mBatteryControllerUnderTest;
-
- StateChangedListener mStateChangedListenerStub = new StateChangedListener() {
- @Override
- public void onControllerStateChanged() {
-
- }
-
- @Override
- public void onTaskDeadlineExpired(TaskStatus taskStatus) {
-
- }
- };
- BatteryController.ChargingTracker mTrackerUnderTest;
-
- public void setUp() throws Exception {
- mBatteryControllerUnderTest = getForTesting(mStateChangedListenerStub, getTestContext());
- mTrackerUnderTest = mBatteryControllerUnderTest.getTracker();
- }
-
- public void testSendBatteryChargingIntent() throws Exception {
- Intent batteryConnectedIntent = new Intent(Intent.ACTION_POWER_CONNECTED)
- .setComponent(new ComponentName(getContext(), mTrackerUnderTest.getClass()));
- Intent batteryHealthyIntent = new Intent(Intent.ACTION_BATTERY_OKAY)
- .setComponent(new ComponentName(getContext(), mTrackerUnderTest.getClass()));
-
- mTrackerUnderTest.onReceiveInternal(batteryConnectedIntent);
- mTrackerUnderTest.onReceiveInternal(batteryHealthyIntent);
-
- assertTrue(mTrackerUnderTest.isOnStablePower());
- }
-
-}
diff --git a/telecomm/java/android/telecomm/CallCapabilities.java b/telecomm/java/android/telecomm/CallCapabilities.java
index b2b33a3..5aff19c 100644
--- a/telecomm/java/android/telecomm/CallCapabilities.java
+++ b/telecomm/java/android/telecomm/CallCapabilities.java
@@ -17,7 +17,7 @@
package android.telecomm;
/** Defines actions a call currently supports. */
-public class CallCapabilities {
+public final class CallCapabilities {
/** Call can currently be put on hold or unheld. */
public static final int HOLD = 0x00000001;
@@ -27,24 +27,60 @@
/** Call can currently be merged. */
public static final int MERGE_CALLS = 0x00000004;
- /* Call can currently be swapped with another call. */
+ /** Call can currently be swapped with another call. */
public static final int SWAP_CALLS = 0x00000008;
- /* Call currently supports adding another call to this one. */
+ /** Call currently supports adding another call to this one. */
public static final int ADD_CALL = 0x00000010;
- /* Call supports responding via text option. */
+ /** Call supports responding via text option. */
public static final int RESPOND_VIA_TEXT = 0x00000020;
- /* Call can be muted. */
+ /** Call can be muted. */
public static final int MUTE = 0x00000040;
- /* Call supports generic conference mode. */
+ /** Call supports generic conference mode. */
public static final int GENERIC_CONFERENCE = 0x00000080;
- /* Call currently supports switch between connections. */
+ /** Call currently supports switch between connections. */
public static final int CONNECTION_HANDOFF = 0x00000100;
public static final int ALL = HOLD | SUPPORT_HOLD | MERGE_CALLS | SWAP_CALLS | ADD_CALL
| RESPOND_VIA_TEXT | MUTE | GENERIC_CONFERENCE | CONNECTION_HANDOFF;
+
+ public static String toString(int capabilities) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("[Capabilities:");
+ if ((capabilities & HOLD) != 0) {
+ builder.append(" HOLD");
+ }
+ if ((capabilities & SUPPORT_HOLD) != 0) {
+ builder.append(" SUPPORT_HOLD");
+ }
+ if ((capabilities & MERGE_CALLS) != 0) {
+ builder.append(" MERGE_CALLS");
+ }
+ if ((capabilities & SWAP_CALLS) != 0) {
+ builder.append(" SWAP_CALLS");
+ }
+ if ((capabilities & ADD_CALL) != 0) {
+ builder.append(" ADD_CALL");
+ }
+ if ((capabilities & RESPOND_VIA_TEXT) != 0) {
+ builder.append(" RESPOND_VIA_TEXT");
+ }
+ if ((capabilities & MUTE) != 0) {
+ builder.append(" MUTE");
+ }
+ if ((capabilities & GENERIC_CONFERENCE) != 0) {
+ builder.append(" GENERIC_CONFERENCE");
+ }
+ if ((capabilities & CONNECTION_HANDOFF) != 0) {
+ builder.append(" HANDOFF");
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+
+ private CallCapabilities() {}
}
diff --git a/telecomm/java/android/telecomm/CallService.java b/telecomm/java/android/telecomm/CallService.java
index a254459..0b5981c 100644
--- a/telecomm/java/android/telecomm/CallService.java
+++ b/telecomm/java/android/telecomm/CallService.java
@@ -61,7 +61,7 @@
private static final int MSG_ON_AUDIO_STATE_CHANGED = 11;
private static final int MSG_PLAY_DTMF_TONE = 12;
private static final int MSG_STOP_DTMF_TONE = 13;
- private static final int MSG_ADD_TO_CONFERENCE = 14;
+ private static final int MSG_CONFERENCE = 14;
private static final int MSG_SPLIT_FROM_CONFERENCE = 15;
private static final int MSG_ON_POST_DIAL_CONTINUE = 16;
@@ -128,24 +128,12 @@
case MSG_STOP_DTMF_TONE:
stopDtmfTone((String) msg.obj);
break;
- case MSG_ADD_TO_CONFERENCE: {
- SomeArgs args = (SomeArgs) msg.obj;
- try {
- @SuppressWarnings("unchecked")
- List<String> callIds = (List<String>) args.arg2;
- String conferenceCallId = (String) args.arg1;
- addToConference(conferenceCallId, callIds);
- } finally {
- args.recycle();
- }
- break;
- }
- case MSG_SPLIT_FROM_CONFERENCE: {
+ case MSG_CONFERENCE: {
SomeArgs args = (SomeArgs) msg.obj;
try {
String conferenceCallId = (String) args.arg1;
String callId = (String) args.arg2;
- splitFromConference(conferenceCallId, callId);
+ conference(conferenceCallId, callId);
} finally {
args.recycle();
}
@@ -162,6 +150,9 @@
}
break;
}
+ case MSG_SPLIT_FROM_CONFERENCE:
+ splitFromConference((String) msg.obj);
+ break;
default:
break;
}
@@ -245,19 +236,16 @@
}
@Override
- public void addToConference(String conferenceCallId, List<String> callsToConference) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = conferenceCallId;
- args.arg2 = callsToConference;
- mMessageHandler.obtainMessage(MSG_ADD_TO_CONFERENCE, args).sendToTarget();
- }
-
- @Override
- public void splitFromConference(String conferenceCallId, String callId) {
+ public void conference(String conferenceCallId, String callId) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = conferenceCallId;
args.arg2 = callId;
- mMessageHandler.obtainMessage(MSG_SPLIT_FROM_CONFERENCE, args).sendToTarget();
+ mMessageHandler.obtainMessage(MSG_CONFERENCE, args).sendToTarget();
+ }
+
+ @Override
+ public void splitFromConference(String callId) {
+ mMessageHandler.obtainMessage(MSG_SPLIT_FROM_CONFERENCE, callId).sendToTarget();
}
@Override
@@ -424,24 +412,22 @@
public abstract void onAudioStateChanged(String activeCallId, CallAudioState audioState);
/**
- * Adds the specified calls to the specified conference call.
+ * Conferences the specified call.
*
* @param conferenceCallId The unique ID of the conference call onto which the specified calls
* should be added.
- * @param callIds The calls to add to the conference call.
+ * @param callId The call to conference.
* @hide
*/
- public abstract void addToConference(String conferenceCallId, List<String> callIds);
+ public abstract void conference(String conferenceCallId, String callId);
/**
- * Removes the specified call from the specified conference call. This is a no-op if the call
- * is not already part of the conference call.
+ * Removes the specified call from a conference call.
*
- * @param conferenceCallId The conference call.
* @param callId The call to remove from the conference call
* @hide
*/
- public abstract void splitFromConference(String conferenceCallId, String callId);
+ public abstract void splitFromConference(String callId);
public void onPostDialContinue(String callId, boolean proceed) {}
public void onPostDialWait(Connection conn, String remaining) {}
diff --git a/telecomm/java/android/telecomm/CallServiceAdapter.java b/telecomm/java/android/telecomm/CallServiceAdapter.java
index fb5c871..0ba8161 100644
--- a/telecomm/java/android/telecomm/CallServiceAdapter.java
+++ b/telecomm/java/android/telecomm/CallServiceAdapter.java
@@ -179,12 +179,12 @@
* Indicates that the specified call can conference with any of the specified list of calls.
*
* @param callId The unique ID of the call.
- * @param conferenceCapableCallIds The unique IDs of the calls which can be conferenced.
+ * @param canConference Specified whether or not the call can be conferenced.
* @hide
*/
- public void setCanConferenceWith(String callId, List<String> conferenceCapableCallIds) {
+ public void setCanConference(String callId, boolean canConference) {
try {
- mAdapter.setCanConferenceWith(callId, conferenceCapableCallIds);
+ mAdapter.setCanConference(callId, canConference);
} catch (RemoteException ignored) {
}
}
@@ -193,13 +193,14 @@
* Indicates whether or not the specified call is currently conferenced into the specified
* conference call.
*
- * @param conferenceCallId The unique ID of the conference call.
* @param callId The unique ID of the call being conferenced.
+ * @param conferenceCallId The unique ID of the conference call. Null if call is not
+ * conferenced.
* @hide
*/
- public void setIsConferenced(String conferenceCallId, String callId, boolean isConferenced) {
+ public void setIsConferenced(String callId, String conferenceCallId) {
try {
- mAdapter.setIsConferenced(conferenceCallId, callId, isConferenced);
+ mAdapter.setIsConferenced(callId, conferenceCallId);
} catch (RemoteException ignored) {
}
}
@@ -224,4 +225,28 @@
} catch (RemoteException ignored) {
}
}
+
+ /**
+ * Instructs Telecomm to handoff the call to another call service.
+ *
+ * @param callId The identifier of the call to handoff.
+ */
+ public void handoffCall(String callId) {
+ try {
+ mAdapter.handoffCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Indicates that a new conference call has been created.
+ *
+ * @param callId The unique ID of the conference call.
+ */
+ public void addConferenceCall(String callId) {
+ try {
+ mAdapter.addConferenceCall(callId, null);
+ } catch (RemoteException ignored) {
+ }
+ }
}
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index 344814f..164eeff 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -19,7 +19,10 @@
import android.net.Uri;
import android.os.Bundle;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
/**
@@ -35,6 +38,8 @@
void onDisconnected(Connection c, int cause, String message);
void onRequestingRingback(Connection c, boolean ringback);
void onDestroyed(Connection c);
+ void onConferenceCapableChanged(Connection c, boolean isConferenceCapable);
+ void onParentConnectionChanged(Connection c, Connection parent);
}
public static class ListenerBase implements Listener {
@@ -65,6 +70,14 @@
/** {@inheritDoc} */
@Override
public void onRequestingRingback(Connection c, boolean ringback) {}
+
+ /** ${inheritDoc} */
+ @Override
+ public void onConferenceCapableChanged(Connection c, boolean isConferenceCapable) {}
+
+ /** ${inheritDoc} */
+ @Override
+ public void onParentConnectionChanged(Connection c, Connection parent) {}
}
public final class State {
@@ -79,10 +92,14 @@
}
private final Set<Listener> mListeners = new HashSet<>();
+ private final List<Connection> mChildConnections = new ArrayList<>();
+
private int mState = State.NEW;
private CallAudioState mCallAudioState;
private Uri mHandle;
private boolean mRequestingRingback = false;
+ private boolean mIsConferenceCapable = false;
+ private Connection mParentConnection;
/**
* Create a new Connection.
@@ -90,6 +107,13 @@
protected Connection() {}
/**
+ * The handle (e.g., phone number) to which this Connection is currently communicating.
+ *
+ * IMPORTANT: If an incoming connection has a phone number (or other handle) that the user
+ * is not supposed to be able to see (e.g. it is PRESENTATION_RESTRICTED), then a compliant
+ * ConnectionService implementation MUST NOT reveal this phone number and MUST return
+ * {@code null} from this method.
+ *
* @return The handle (e.g., phone number) to which this Connection
* is currently communicating.
*/
@@ -176,6 +200,16 @@
}
/**
+ * Separates this Connection from a parent connection.
+ *
+ * @hide
+ */
+ public final void separate() {
+ Log.d(this, "separate");
+ onSeparate();
+ }
+
+ /**
* Abort this Connection. The Connection will immediately transition to
* the {@link State#DISCONNECTED} state, and send no notifications of this
* or any other future events.
@@ -240,6 +274,14 @@
}
/**
+ * TODO(santoscordon): Needs updated documentation.
+ */
+ public final void conference() {
+ Log.d(this, "conference");
+ onConference();
+ }
+
+ /**
* Inform this Connection that the state of its audio output has been changed externally.
*
* @param state The new audio state.
@@ -274,7 +316,7 @@
}
/**
- * @return Whether this connection is requesting that the system play a ringback tone
+ * Returns whether this connection is requesting that the system play a ringback tone
* on its behalf.
*/
public boolean isRequestingRingback() {
@@ -282,6 +324,38 @@
}
/**
+ * Returns whether this connection is a conference connection (has child connections).
+ */
+ public boolean isConferenceConnection() {
+ return !mChildConnections.isEmpty();
+ }
+
+ public void setParentConnection(Connection parentConnection) {
+ Log.d(this, "parenting %s to %s", this, parentConnection);
+ if (mParentConnection != parentConnection) {
+ if (mParentConnection != null) {
+ mParentConnection.removeChild(this);
+ }
+ mParentConnection = parentConnection;
+ if (mParentConnection != null) {
+ mParentConnection.addChild(this);
+ // do something if the child connections goes down to ZERO.
+ }
+ for (Listener l : mListeners) {
+ l.onParentConnectionChanged(this, mParentConnection);
+ }
+ }
+ }
+
+ public Connection getParentConnection() {
+ return mParentConnection;
+ }
+
+ public List<Connection> getChildConnections() {
+ return mChildConnections;
+ }
+
+ /**
* Sets the value of the {@link #getHandle()} property and notifies listeners.
*
* @param handle The new handle.
@@ -359,6 +433,32 @@
}
/**
+ * TODO(santoscordon): Needs documentation.
+ */
+ protected void setIsConferenceCapable(boolean isConferenceCapable) {
+ if (mIsConferenceCapable != isConferenceCapable) {
+ mIsConferenceCapable = isConferenceCapable;
+ for (Listener l : mListeners) {
+ l.onConferenceCapableChanged(this, mIsConferenceCapable);
+ }
+ }
+ }
+
+ /**
+ * TODO(santoscordon): Needs documentation.
+ */
+ protected void setDestroyed() {
+ // It is possible that onDestroy() will trigger the listener to remove itself which will
+ // result in a concurrent modification exception. To counteract this we make a copy of the
+ // listeners and iterate on that.
+ for (Listener l : new ArrayList<>(mListeners)) {
+ if (mListeners.contains(l)) {
+ l.onDestroyed(this);
+ }
+ }
+ }
+
+ /**
* Notifies this Connection and listeners that the {@link #getCallAudioState()} property
* has a new value.
*
@@ -418,6 +518,11 @@
protected void onDisconnect() {}
/**
+ * Notifies this Connection of a request to disconnect.
+ */
+ protected void onSeparate() {}
+
+ /**
* Notifies this Connection of a request to abort.
*/
protected void onAbort() {}
@@ -449,6 +554,28 @@
*/
protected void onPostDialContinue(boolean proceed) {}
+ /**
+ * TODO(santoscordon): Needs documentation.
+ */
+ protected void onConference() {}
+
+ /**
+ * TODO(santoscordon): Needs documentation.
+ */
+ protected void onChildrenChanged(List<Connection> children) {}
+
+ private void addChild(Connection connection) {
+ Log.d(this, "adding child %s", connection);
+ mChildConnections.add(connection);
+ onChildrenChanged(mChildConnections);
+ }
+
+ private void removeChild(Connection connection) {
+ Log.d(this, "removing child %s", connection);
+ mChildConnections.remove(connection);
+ onChildrenChanged(mChildConnections);
+ }
+
private void setState(int state) {
Log.d(this, "setState: %s", stateToString(state));
onSetState(state);
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index 59e977d..d974509 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -20,10 +20,15 @@
import android.os.Bundle;
import android.telephony.DisconnectCause;
+import android.os.SystemClock;
+
+import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* A {@link android.app.Service} that provides telephone connections to
@@ -32,7 +37,6 @@
public abstract class ConnectionService extends CallService {
// Flag controlling whether PII is emitted into the logs
private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
-
private static final Connection NULL_CONNECTION = new Connection() {};
// Mappings from Connections to IDs as understood by the current CallService implementation
@@ -99,6 +103,20 @@
Log.d(this, "Adapter onRingback %b", ringback);
getAdapter().setRequestingRingback(id, ringback);
}
+
+ @Override
+ public void onConferenceCapableChanged(Connection c, boolean isConferenceCapable) {
+ String id = mIdByConnection.get(c);
+ getAdapter().setCanConference(id, isConferenceCapable);
+ }
+
+ /** ${inheritDoc} */
+ @Override
+ public void onParentConnectionChanged(Connection c, Connection parent) {
+ String id = mIdByConnection.get(c);
+ String parentId = parent == null ? null : mIdByConnection.get(parent);
+ getAdapter().setIsConferenced(id, parentId);
+ }
};
@Override
@@ -110,8 +128,7 @@
@Override
public void onResult(Uri handle, Subscription... result) {
boolean isCompatible = result.length > 0;
- Log.d(this, "adapter setIsCompatibleWith "
- + callInfo.getId() + " " + isCompatible);
+ Log.d(this, "adapter setIsCompatibleWith ");
getAdapter().setIsCompatibleWith(callInfo.getId(), isCompatible);
}
@@ -135,7 +152,7 @@
new Response<ConnectionRequest, Connection>() {
@Override
public void onResult(ConnectionRequest request, Connection... result) {
- if (result.length != 1) {
+ if (result != null && result.length != 1) {
Log.d(this, "adapter handleFailedOutgoingCall %s", callInfo);
getAdapter().handleFailedOutgoingCall(
request,
@@ -145,10 +162,10 @@
c.abort();
}
} else {
- addConnection(callInfo.getId(), result[0]);
Log.d(this, "adapter handleSuccessfulOutgoingCall %s",
callInfo.getId());
getAdapter().handleSuccessfulOutgoingCall(callInfo.getId());
+ addConnection(callInfo.getId(), result[0]);
}
}
@@ -177,7 +194,7 @@
new Response<ConnectionRequest, Connection>() {
@Override
public void onResult(ConnectionRequest request, Connection... result) {
- if (result.length != 1) {
+ if (result != null && result.length != 1) {
Log.d(this, "adapter handleFailedOutgoingCall %s", callId);
getAdapter().handleFailedOutgoingCall(
request,
@@ -258,27 +275,43 @@
/** @hide */
@Override
- public final void addToConference(String conferenceCallId, List<String> callIds) {
- Log.d(this, "addToConference %s, %s", conferenceCallId, callIds);
+ public final void conference(final String conferenceCallId, String callId) {
+ Log.d(this, "conference %s, %s", conferenceCallId, callId);
- List<Connection> connections = new LinkedList<>();
- for (String id : callIds) {
- Connection connection = findConnectionForAction(id, "addToConference");
- if (connection == NULL_CONNECTION) {
- Log.w(this, "Connection missing in conference request %s.", id);
- return;
- }
- connections.add(connection);
+ Connection connection = findConnectionForAction(callId, "conference");
+ if (connection == NULL_CONNECTION) {
+ Log.w(this, "Connection missing in conference request %s.", callId);
+ return;
}
- // TODO(santoscordon): Find an existing conference call or create a new one. Then call
- // conferenceWith on it.
+ onCreateConferenceConnection(conferenceCallId, connection,
+ new Response<String, Connection>() {
+ /** ${inheritDoc} */
+ @Override
+ public void onResult(String ignored, Connection... result) {
+ Log.d(this, "onCreateConference.Response %s", (Object[]) result);
+ if (result != null && result.length == 1) {
+ Connection conferenceConnection = result[0];
+ if (!mIdByConnection.containsKey(conferenceConnection)) {
+ Log.v(this, "sending new conference call %s", conferenceCallId);
+ getAdapter().addConferenceCall(conferenceCallId);
+ addConnection(conferenceCallId, conferenceConnection);
+ }
+ }
+ }
+
+ /** ${inheritDoc} */
+ @Override
+ public void onError(String request, int code, String reason) {
+ // no-op
+ }
+ });
}
/** @hide */
@Override
- public final void splitFromConference(String conferenceCallId, String callId) {
- Log.d(this, "splitFromConference(%s, %s)", conferenceCallId, callId);
+ public final void splitFromConference(String callId) {
+ Log.d(this, "splitFromConference(%s)", callId);
Connection connection = findConnectionForAction(callId, "splitFromConference");
if (connection == NULL_CONNECTION) {
@@ -309,6 +342,13 @@
}
/**
+ * Returns all connections currently associated with this connection service.
+ */
+ public Collection<Connection> getAllConnections() {
+ return mConnectionById.values();
+ }
+
+ /**
* Find a set of Subscriptions matching a given handle (e.g. phone number).
*
* @param handle A handle (e.g. phone number) with which to connect.
@@ -329,8 +369,28 @@
Response<ConnectionRequest, Connection> callback) {}
/**
+ * Returns a new or existing conference connection when the the user elects to convert the
+ * specified connection into a conference call. The specified connection can be any connection
+ * which had previously specified itself as conference-capable including both simple connections
+ * and connections previously returned from this method.
+ *
+ * @param connection The connection from which the user opted to start a conference call.
+ * @param token The token to be passed into the response callback.
+ * @param callback The callback for providing the potentially-new conference connection.
+ */
+ public void onCreateConferenceConnection(
+ String token,
+ Connection connection,
+ Response<String, Connection> callback) {}
+
+ /**
* Create a Connection to match an incoming connection notification.
*
+ * IMPORTANT: If the incoming connection has a phone number (or other handle) that the user
+ * is not supposed to be able to see (e.g. it is PRESENTATION_RESTRICTED), then a compliant
+ * ConnectionService implementation MUST NOT reveal this phone number as part of the Intent
+ * it sends to notify Telecomm of an incoming connection.
+ *
* @param request Data encapsulating details of the desired Connection.
* @param callback A callback for providing the result.
*/
@@ -338,6 +398,20 @@
ConnectionRequest request,
Response<ConnectionRequest, Connection> callback) {}
+ /**
+ * Notifies that a connection has been added to this connection service and sent to Telecomm.
+ *
+ * @param connection The connection which was added.
+ */
+ public void onConnectionAdded(Connection connection) {}
+
+ /**
+ * Notified that a connection has been removed from this connection service.
+ *
+ * @param connection The connection which was removed.
+ */
+ public void onConnectionRemoved(Connection connection) {}
+
static String toLogSafePhoneNumber(String number) {
// For unknown number, log empty string.
if (number == null) {
@@ -387,12 +461,14 @@
mConnectionById.put(callId, connection);
mIdByConnection.put(connection, callId);
connection.addConnectionListener(mConnectionListener);
+ onConnectionAdded(connection);
}
private void removeConnection(Connection connection) {
connection.removeConnectionListener(mConnectionListener);
mConnectionById.remove(mIdByConnection.get(connection));
mIdByConnection.remove(connection);
+ onConnectionRemoved(connection);
}
private Connection findConnectionForAction(String callId, String action) {
diff --git a/telecomm/java/android/telecomm/InCallAdapter.java b/telecomm/java/android/telecomm/InCallAdapter.java
index 0bef419..ce52d19 100644
--- a/telecomm/java/android/telecomm/InCallAdapter.java
+++ b/telecomm/java/android/telecomm/InCallAdapter.java
@@ -59,10 +59,12 @@
* is ported over.
*
* @param callId The identifier of the call to reject.
+ * @param rejectWithMessage Whether to reject with a text message.
+ * @param textMessage An optional text message with which to respond.
*/
- public void rejectCall(String callId) {
+ public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) {
try {
- mAdapter.rejectCall(callId);
+ mAdapter.rejectCall(callId, rejectWithMessage, textMessage);
} catch (RemoteException e) {
}
}
@@ -199,15 +201,14 @@
}
/**
- * Instructs Telecomm to conference the specified calls together.
+ * Instructs Telecomm to conference the specified call.
*
* @param callId The unique ID of the call.
- * @param callIdToConference The unique ID of the call to conference with.
* @hide
*/
- void conferenceWith(String callId, String callIdToConference) {
+ public void conference(String callId) {
try {
- mAdapter.conferenceWith(callId, callIdToConference);
+ mAdapter.conference(callId);
} catch (RemoteException ignored) {
}
}
@@ -219,7 +220,7 @@
* @param callId The unique ID of the call.
* @hide
*/
- void splitFromConference(String callId) {
+ public void splitFromConference(String callId) {
try {
mAdapter.splitFromConference(callId);
} catch (RemoteException ignored) {
diff --git a/telecomm/java/android/telecomm/InCallCall.java b/telecomm/java/android/telecomm/InCallCall.java
index b531ccd..66974f9 100644
--- a/telecomm/java/android/telecomm/InCallCall.java
+++ b/telecomm/java/android/telecomm/InCallCall.java
@@ -33,13 +33,13 @@
private final CallState mState;
private final int mDisconnectCauseCode;
private final String mDisconnectCauseMsg;
+ private final List<String> mCannedSmsResponses;
private final int mCapabilities;
private final long mConnectTimeMillis;
private final Uri mHandle;
private final GatewayInfo mGatewayInfo;
private final CallServiceDescriptor mCurrentCallServiceDescriptor;
private final CallServiceDescriptor mHandoffCallServiceDescriptor;
- private final List<String> mConferenceCapableCallIds;
private final String mParentCallId;
private final List<String> mChildCallIds;
@@ -50,15 +50,16 @@
CallState state,
int disconnectCauseCode,
String disconnectCauseMsg,
+ List<String> cannedSmsResponses,
int capabilities,
long connectTimeMillis,
Uri handle,
GatewayInfo gatewayInfo,
CallServiceDescriptor descriptor,
CallServiceDescriptor handoffDescriptor) {
- this(id, state, disconnectCauseCode, disconnectCauseMsg, capabilities, connectTimeMillis,
- handle, gatewayInfo, descriptor, handoffDescriptor, Collections.EMPTY_LIST, null,
- Collections.EMPTY_LIST);
+ this(id, state, disconnectCauseCode, disconnectCauseMsg, cannedSmsResponses,
+ capabilities, connectTimeMillis, handle, gatewayInfo, descriptor, handoffDescriptor,
+ null, Collections.EMPTY_LIST);
}
/** @hide */
@@ -67,26 +68,26 @@
CallState state,
int disconnectCauseCode,
String disconnectCauseMsg,
+ List<String> cannedSmsResponses,
int capabilities,
long connectTimeMillis,
Uri handle,
GatewayInfo gatewayInfo,
CallServiceDescriptor descriptor,
CallServiceDescriptor handoffDescriptor,
- List<String> conferenceCapableCallIds,
String parentCallId,
List<String> childCallIds) {
mId = id;
mState = state;
mDisconnectCauseCode = disconnectCauseCode;
mDisconnectCauseMsg = disconnectCauseMsg;
+ mCannedSmsResponses = cannedSmsResponses;
mCapabilities = capabilities;
mConnectTimeMillis = connectTimeMillis;
mHandle = handle;
mGatewayInfo = gatewayInfo;
mCurrentCallServiceDescriptor = descriptor;
mHandoffCallServiceDescriptor = handoffDescriptor;
- mConferenceCapableCallIds = conferenceCapableCallIds;
mParentCallId = parentCallId;
mChildCallIds = childCallIds;
}
@@ -117,6 +118,13 @@
return mDisconnectCauseMsg;
}
+ /**
+ * The set of possible text message responses when this call is incoming.
+ */
+ public List<String> getCannedSmsResponses() {
+ return mCannedSmsResponses;
+ }
+
// Bit mask of actions a call supports, values are defined in {@link CallCapabilities}.
public int getCapabilities() {
return mCapabilities;
@@ -151,14 +159,6 @@
}
/**
- * The calls with which this call can conference.
- * @hide
- */
- public List<String> getConferenceCapableCallIds() {
- return mConferenceCapableCallIds;
- }
-
- /**
* The conference call to which this call is conferenced. Null if not conferenced.
* @hide
*/
@@ -180,25 +180,25 @@
new Parcelable.Creator<InCallCall> () {
@Override
public InCallCall createFromParcel(Parcel source) {
+ ClassLoader classLoader = InCallCall.class.getClassLoader();
String id = source.readString();
CallState state = CallState.valueOf(source.readString());
int disconnectCauseCode = source.readInt();
String disconnectCauseMsg = source.readString();
+ List<String> cannedSmsResponses = new ArrayList<>();
+ source.readList(cannedSmsResponses, classLoader);
int capabilities = source.readInt();
long connectTimeMillis = source.readLong();
- ClassLoader classLoader = InCallCall.class.getClassLoader();
Uri handle = source.readParcelable(classLoader);
GatewayInfo gatewayInfo = source.readParcelable(classLoader);
CallServiceDescriptor descriptor = source.readParcelable(classLoader);
CallServiceDescriptor handoffDescriptor = source.readParcelable(classLoader);
- List<String> conferenceCapableCallIds = new ArrayList<>();
- source.readList(conferenceCapableCallIds, classLoader);
String parentCallId = source.readString();
List<String> childCallIds = new ArrayList<>();
source.readList(childCallIds, classLoader);
- return new InCallCall(id, state, disconnectCauseCode, disconnectCauseMsg, capabilities,
- connectTimeMillis, handle, gatewayInfo, descriptor, handoffDescriptor,
- conferenceCapableCallIds, parentCallId, childCallIds);
+ return new InCallCall(id, state, disconnectCauseCode, disconnectCauseMsg,
+ cannedSmsResponses, capabilities, connectTimeMillis, handle, gatewayInfo,
+ descriptor, handoffDescriptor, parentCallId, childCallIds);
}
@Override
@@ -220,14 +220,19 @@
destination.writeString(mState.name());
destination.writeInt(mDisconnectCauseCode);
destination.writeString(mDisconnectCauseMsg);
+ destination.writeList(mCannedSmsResponses);
destination.writeInt(mCapabilities);
destination.writeLong(mConnectTimeMillis);
destination.writeParcelable(mHandle, 0);
destination.writeParcelable(mGatewayInfo, 0);
destination.writeParcelable(mCurrentCallServiceDescriptor, 0);
destination.writeParcelable(mHandoffCallServiceDescriptor, 0);
- destination.writeList(mConferenceCapableCallIds);
destination.writeString(mParentCallId);
destination.writeList(mChildCallIds);
}
+
+ @Override
+ public String toString() {
+ return String.format("[%s, parent:%s, children:%s]", mId, mParentCallId, mChildCallIds);
+ }
}
diff --git a/telecomm/java/android/telecomm/PhoneApplication.java b/telecomm/java/android/telecomm/PhoneApplication.java
new file mode 100644
index 0000000..1da54e0
--- /dev/null
+++ b/telecomm/java/android/telecomm/PhoneApplication.java
@@ -0,0 +1,183 @@
+package android.telecomm;
+
+import android.annotation.SystemApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.telecomm.ITelecommService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class for managing the primary phone application that will receive incoming calls, and be allowed
+ * to make emergency outgoing calls.
+ *
+ * @hide
+ */
+public class PhoneApplication {
+ private static final String TAG = PhoneApplication.class.getSimpleName();
+ private static final String TELECOMM_SERVICE_NAME = "telecomm";
+
+ /**
+ * Sets the specified package name as the default phone application. The caller of this method
+ * needs to have permission to write to secure settings.
+ *
+ * @hide
+ * */
+ @SystemApi
+ public static void setDefaultPhoneApplication(String packageName, Context context) {
+ // Get old package name
+ String oldPackageName = Settings.Secure.getString(context.getContentResolver(),
+ Settings.Secure.PHONE_DEFAULT_APPLICATION);
+
+ if (packageName != null && oldPackageName != null && packageName.equals(oldPackageName)) {
+ // No change
+ return;
+ }
+
+ // Only make the change if the new package belongs to a valid phone application
+ List<ComponentName> componentNames = getInstalledPhoneApplications(context);
+ ComponentName foundComponent = null;
+ for (ComponentName componentName : componentNames) {
+ if (TextUtils.equals(componentName.getPackageName(), packageName)) {
+ foundComponent = componentName;
+ break;
+ }
+ }
+
+ if (foundComponent != null) {
+ // Update the secure setting.
+ Settings.Secure.putString(context.getContentResolver(),
+ Settings.Secure.PHONE_DEFAULT_APPLICATION, foundComponent.getPackageName());
+ }
+ }
+
+ /**
+ * Returns the installed phone application that will be used to receive incoming calls, and is
+ * allowed to make emergency calls.
+ *
+ * The application will be returned in order of preference:
+ * 1) User selected phone application (if still installed)
+ * 2) Pre-installed system dialer (if not disabled)
+ * 3) Null
+ *
+ * @hide
+ * */
+ @SystemApi
+ public static ComponentName getDefaultPhoneApplication(Context context) {
+ String defaultPackageName = Settings.Secure.getString(context.getContentResolver(),
+ Settings.Secure.PHONE_DEFAULT_APPLICATION);
+
+ final List<ComponentName> componentNames = getInstalledPhoneApplications(context);
+ if (!TextUtils.isEmpty(defaultPackageName)) {
+ for (ComponentName componentName : componentNames) {
+ if (TextUtils.equals(componentName.getPackageName(), defaultPackageName)) {
+ return componentName;
+ }
+ }
+ }
+
+ // No user-set dialer found, fallback to system dialer
+ ComponentName systemDialer = null;
+ try {
+ systemDialer = getTelecommService().getSystemPhoneApplication();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecommService#getSystemPhoneApplication", e);
+ return null;
+ }
+
+ if (systemDialer == null) {
+ // No system dialer configured at build time
+ return null;
+ }
+
+ // Verify that the system dialer has not been disabled.
+ return getComponentName(componentNames, systemDialer.getPackageName());
+ }
+
+ /**
+ * Returns a list of installed and available phone applications.
+ *
+ * In order to appear in the list, a phone application must implement an intent-filter with
+ * the DIAL intent for the following schemes:
+ *
+ * 1) Empty scheme
+ * 2) tel Uri scheme
+ *
+ * @hide
+ **/
+ @SystemApi
+ public static List<ComponentName> getInstalledPhoneApplications(Context context) {
+ PackageManager packageManager = context.getPackageManager();
+
+ // Get the list of apps registered for the DIAL intent with empty scheme
+ Intent intent = new Intent(Intent.ACTION_DIAL);
+ List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0);
+
+ List<ComponentName> componentNames = new ArrayList<ComponentName> ();
+
+ for (ResolveInfo resolveInfo : resolveInfoList) {
+ final ActivityInfo activityInfo = resolveInfo.activityInfo;
+ if (activityInfo == null) {
+ continue;
+ }
+ final ComponentName componentName =
+ new ComponentName(activityInfo.packageName, activityInfo.name);
+ componentNames.add(componentName);
+ }
+
+ // TODO: Filter for apps that don't handle DIAL intent with tel scheme
+ return componentNames;
+ }
+
+ /**
+ * Returns the {@link ComponentName} for the installed phone application for a given package
+ * name.
+ *
+ * @param context A valid context.
+ * @param packageName to retrieve the {@link ComponentName} for.
+ *
+ * @return The {@link ComponentName} for the installed phone application corresponding to the
+ * package name, or null if none is found.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static ComponentName getPhoneApplicationForPackageName(Context context,
+ String packageName) {
+ return getComponentName(getInstalledPhoneApplications(context), packageName);
+ }
+
+ /**
+ * Returns the component from a list of application components that corresponds to the package
+ * name.
+ *
+ * @param componentNames A list of component names
+ * @param packageName The package name to look for
+ * @return The {@link ComponentName} that matches the provided packageName, or null if not
+ * found.
+ */
+ private static ComponentName getComponentName(List<ComponentName> componentNames,
+ String packageName) {
+ for (ComponentName componentName : componentNames) {
+ if (TextUtils.equals(packageName, componentName.getPackageName())) {
+ return componentName;
+ }
+ }
+ return null;
+ }
+
+ private static ITelecommService getTelecommService() {
+ return ITelecommService.Stub.asInterface(ServiceManager.getService(TELECOMM_SERVICE_NAME));
+ }
+}
diff --git a/telecomm/java/android/telecomm/TelecommConstants.java b/telecomm/java/android/telecomm/TelecommConstants.java
index 8300c92..0952097 100644
--- a/telecomm/java/android/telecomm/TelecommConstants.java
+++ b/telecomm/java/android/telecomm/TelecommConstants.java
@@ -16,6 +16,7 @@
package android.telecomm;
+import android.content.Intent;
import android.os.Bundle;
import android.telephony.TelephonyManager;
@@ -55,6 +56,28 @@
public static final String ACTION_CALL_SERVICE_SELECTOR = CallServiceSelector.class.getName();
/**
+ * Activity action: Ask the user to change the default phone application. This will show a
+ * dialog that asks the user whether they want to replace the current default phone application
+ * with the one defined in {@link #EXTRA_PACKAGE_NAME}.
+ */
+ public static final String ACTION_CHANGE_DEFAULT_PHONE =
+ "android.telecomm.ACTION_CHANGE_DEFAULT_PHONE";
+
+ /**
+ * The PackageName string passed in as an extra for {@link #ACTION_CHANGE_DEFAULT_PHONE}.
+ *
+ * @see #ACTION_CHANGE_DEFAULT_PHONE
+ */
+ public static final String EXTRA_PACKAGE_NAME = "package";
+
+ /**
+ * Optional extra for {@link Intent#ACTION_CALL} containing a boolean that determines whether
+ * the speakerphone should be automatically turned on for an outgoing call.
+ */
+ public static final String EXTRA_START_CALL_WITH_SPEAKERPHONE =
+ "android.intent.extra.START_CALL_WITH_SPEAKERPHONE";
+
+ /**
* Extra for {@link #ACTION_INCOMING_CALL} containing the {@link CallServiceDescriptor} that
* describes the call service to use for the incoming call.
*/
diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java
new file mode 100644
index 0000000..a97e7e4
--- /dev/null
+++ b/telecomm/java/android/telecomm/TelecommManager.java
@@ -0,0 +1,48 @@
+/*
+ * 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.telecomm;
+
+import android.content.Context;
+
+import com.android.internal.telecomm.ITelecommService;
+
+/**
+ * Provides access to Telecomm-related functionality.
+ */
+public class TelecommManager {
+ private static final String TAG = "TelecommManager";
+
+ private final Context mContext;
+ private final ITelecommService mService;
+
+ /** @hide */
+ public TelecommManager(Context context, ITelecommService service) {
+ Context appContext = context.getApplicationContext();
+ if (appContext != null) {
+ mContext = appContext;
+ } else {
+ mContext = context;
+ }
+
+ mService = service;
+ }
+
+ /** {@hide} */
+ public static TelecommManager from(Context context) {
+ return (TelecommManager) context.getSystemService(Context.TELECOMM_SERVICE);
+ }
+}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallService.aidl b/telecomm/java/com/android/internal/telecomm/ICallService.aidl
index 9139aa6..827f331 100644
--- a/telecomm/java/com/android/internal/telecomm/ICallService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ICallService.aidl
@@ -56,9 +56,9 @@
void stopDtmfTone(String callId);
- void addToConference(String conferenceCallId, in List<String> callIds);
+ void conference(String conferenceCallId, String callId);
- void splitFromConference(String conferenceCallId, String callId);
+ void splitFromConference(String callId);
void onPostDialContinue(String callId, boolean proceed);
}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
index 17e0487..6e176eb 100644
--- a/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
@@ -47,11 +47,15 @@
void setRequestingRingback(String callId, boolean ringing);
- void setCanConferenceWith(String callId, in List<String> conferenceCapableCallIds);
+ void setCanConference(String callId, boolean canConference);
- void setIsConferenced(String conferenceCallId, String callId, boolean isConferenced);
+ void setIsConferenced(String callId, String conferenceCallId);
+
+ void addConferenceCall(String callId, in CallInfo callInfo);
void removeCall(String callId);
void onPostDialWait(String callId, String remaining);
+
+ void handoffCall(String callId);
}
diff --git a/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
index f144043..b66995a 100644
--- a/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
@@ -28,7 +28,7 @@
oneway interface IInCallAdapter {
void answerCall(String callId);
- void rejectCall(String callId);
+ void rejectCall(String callId, boolean rejectWithMessage, String textMessage);
void disconnectCall(String callId);
@@ -48,7 +48,7 @@
void handoffCall(String callId);
- void conferenceWith(String callId, String callIdToConference);
+ void conference(String callId);
void splitFromConference(String callId);
}
diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
index 0e94ffb..638b86a 100644
--- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
@@ -16,6 +16,8 @@
package com.android.internal.telecomm;
+import android.content.ComponentName;
+
/**
* Interface used to interact with Telecomm. Mostly this is used by TelephonyManager for passing
* commands that were previously handled by ITelephony.
@@ -38,4 +40,9 @@
* @param showDialpad if true, make the dialpad visible initially.
*/
void showCallScreen(boolean showDialpad);
+
+ /**
+ * Returns the component name of the phone application installed on the system partition.
+ */
+ ComponentName getSystemPhoneApplication();
}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index ed7f6b8..b935d2a 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -36,6 +36,7 @@
import android.telephony.Rlog;
import android.util.SparseIntArray;
+import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_IDP_STRING;
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
@@ -166,7 +167,9 @@
// TODO: We don't check for SecurityException here (requires
// CALL_PRIVILEGED permission).
if (scheme.equals("voicemail")) {
- return TelephonyManager.getDefault().getCompleteVoiceMailNumber();
+ long subId = intent.getLongExtra(SUBSCRIPTION_KEY,
+ SubscriptionManager.getDefaultVoiceSubId());
+ return TelephonyManager.getDefault().getCompleteVoiceMailNumber(subId);
}
if (context == null) {
@@ -1144,7 +1147,7 @@
* @return A locally acceptable formatting of the input, or the raw input if
* formatting rules aren't known for the number
*
- * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+ * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
*/
public static String formatNumber(String source) {
SpannableStringBuilder text = new SpannableStringBuilder(source);
@@ -1162,7 +1165,7 @@
* @return The phone number formatted with the given formatting type.
*
* @hide
- * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+ * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
*/
public static String formatNumber(String source, int defaultFormattingType) {
SpannableStringBuilder text = new SpannableStringBuilder(source);
@@ -1177,7 +1180,7 @@
* @return The formatting type for the given locale, or FORMAT_UNKNOWN if the formatting
* rules are not known for the given locale
*
- * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+ * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
*/
public static int getFormatTypeForLocale(Locale locale) {
String country = locale.getCountry();
@@ -1193,7 +1196,7 @@
* @param defaultFormattingType The default formatting rules to apply if the number does
* not begin with +[country_code]
*
- * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+ * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
*/
public static void formatNumber(Editable text, int defaultFormattingType) {
int formatType = defaultFormattingType;
@@ -1241,7 +1244,7 @@
*
* @param text the number to be formatted, will be modified with the formatting
*
- * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+ * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
*/
public static void formatNanpNumber(Editable text) {
int length = text.length();
@@ -1356,7 +1359,7 @@
* @param text the number to be formatted, will be modified with
* the formatting
*
- * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+ * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
*/
public static void formatJapaneseNumber(Editable text) {
JapanesePhoneNumberFormatter.format(text);
@@ -1560,9 +1563,23 @@
* listed in the RIL / SIM, otherwise return false.
*/
public static boolean isEmergencyNumber(String number) {
+ return isEmergencyNumber(getDefaultVoiceSubId(), number);
+ }
+
+ /**
+ * Checks a given number against the list of
+ * emergency numbers provided by the RIL and SIM card.
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @return true if the number is in the list of emergency numbers
+ * listed in the RIL / SIM, otherwise return false.
+ * @hide
+ */
+ public static boolean isEmergencyNumber(long subId, String number) {
// Return true only if the specified number *exactly* matches
// one of the emergency numbers listed by the RIL / SIM.
- return isEmergencyNumberInternal(number, true /* useExactMatch */);
+ return isEmergencyNumberInternal(subId, number, true /* useExactMatch */);
}
/**
@@ -1586,9 +1603,33 @@
* @hide
*/
public static boolean isPotentialEmergencyNumber(String number) {
+ return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number);
+ }
+
+ /**
+ * Checks if given number might *potentially* result in
+ * a call to an emergency service on the current network.
+ *
+ * Specifically, this method will return true if the specified number
+ * is an emergency number according to the list managed by the RIL or
+ * SIM, *or* if the specified number simply starts with the same
+ * digits as any of the emergency numbers listed in the RIL / SIM.
+ *
+ * This method is intended for internal use by the phone app when
+ * deciding whether to allow ACTION_CALL intents from 3rd party apps
+ * (where we're required to *not* allow emergency calls to be placed.)
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @return true if the number is in the list of emergency numbers
+ * listed in the RIL / SIM, *or* if the number starts with the
+ * same digits as any of those emergency numbers.
+ * @hide
+ */
+ public static boolean isPotentialEmergencyNumber(long subId, String number) {
// Check against the emergency numbers listed by the RIL / SIM,
// and *don't* require an exact match.
- return isEmergencyNumberInternal(number, false /* useExactMatch */);
+ return isEmergencyNumberInternal(subId, number, false /* useExactMatch */);
}
/**
@@ -1611,7 +1652,32 @@
* listed in the RIL / sim, otherwise return false.
*/
private static boolean isEmergencyNumberInternal(String number, boolean useExactMatch) {
- return isEmergencyNumberInternal(number, null, useExactMatch);
+ return isEmergencyNumberInternal(getDefaultVoiceSubId(), number, useExactMatch);
+ }
+
+ /**
+ * Helper function for isEmergencyNumber(String) and
+ * isPotentialEmergencyNumber(String).
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ *
+ * @param useExactMatch if true, consider a number to be an emergency
+ * number only if it *exactly* matches a number listed in
+ * the RIL / SIM. If false, a number is considered to be an
+ * emergency number if it simply starts with the same digits
+ * as any of the emergency numbers listed in the RIL / SIM.
+ * (Setting useExactMatch to false allows you to identify
+ * number that could *potentially* result in emergency calls
+ * since many networks will actually ignore trailing digits
+ * after a valid emergency number.)
+ *
+ * @return true if the number is in the list of emergency numbers
+ * listed in the RIL / sim, otherwise return false.
+ */
+ private static boolean isEmergencyNumberInternal(long subId, String number,
+ boolean useExactMatch) {
+ return isEmergencyNumberInternal(subId, number, null, useExactMatch);
}
/**
@@ -1625,7 +1691,21 @@
* @hide
*/
public static boolean isEmergencyNumber(String number, String defaultCountryIso) {
- return isEmergencyNumberInternal(number,
+ return isEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso);
+ }
+
+ /**
+ * Checks if a given number is an emergency number for a specific country.
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @param defaultCountryIso the specific country which the number should be checked against
+ * @return if the number is an emergency number for the specific country, then return true,
+ * otherwise false
+ * @hide
+ */
+ public static boolean isEmergencyNumber(long subId, String number, String defaultCountryIso) {
+ return isEmergencyNumberInternal(subId, number,
defaultCountryIso,
true /* useExactMatch */);
}
@@ -1652,7 +1732,33 @@
* @hide
*/
public static boolean isPotentialEmergencyNumber(String number, String defaultCountryIso) {
- return isEmergencyNumberInternal(number,
+ return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso);
+ }
+
+ /**
+ * Checks if a given number might *potentially* result in a call to an
+ * emergency service, for a specific country.
+ *
+ * Specifically, this method will return true if the specified number
+ * is an emergency number in the specified country, *or* if the number
+ * simply starts with the same digits as any emergency number for that
+ * country.
+ *
+ * This method is intended for internal use by the phone app when
+ * deciding whether to allow ACTION_CALL intents from 3rd party apps
+ * (where we're required to *not* allow emergency calls to be placed.)
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @param defaultCountryIso the specific country which the number should be checked against
+ * @return true if the number is an emergency number for the specific
+ * country, *or* if the number starts with the same digits as
+ * any of those emergency numbers.
+ * @hide
+ */
+ public static boolean isPotentialEmergencyNumber(long subId, String number,
+ String defaultCountryIso) {
+ return isEmergencyNumberInternal(subId, number,
defaultCountryIso,
false /* useExactMatch */);
}
@@ -1674,6 +1780,29 @@
private static boolean isEmergencyNumberInternal(String number,
String defaultCountryIso,
boolean useExactMatch) {
+ return isEmergencyNumberInternal(getDefaultVoiceSubId(), number, defaultCountryIso,
+ useExactMatch);
+ }
+
+ /**
+ * Helper function for isEmergencyNumber(String, String) and
+ * isPotentialEmergencyNumber(String, String).
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @param defaultCountryIso the specific country which the number should be checked against
+ * @param useExactMatch if true, consider a number to be an emergency
+ * number only if it *exactly* matches a number listed in
+ * the RIL / SIM. If false, a number is considered to be an
+ * emergency number if it simply starts with the same digits
+ * as any of the emergency numbers listed in the RIL / SIM.
+ *
+ * @return true if the number is an emergency number for the specified country.
+ * @hide
+ */
+ private static boolean isEmergencyNumberInternal(long subId, String number,
+ String defaultCountryIso,
+ boolean useExactMatch) {
// If the number passed in is null, just return false:
if (number == null) return false;
@@ -1692,9 +1821,14 @@
// to the list.
number = extractNetworkPortionAlt(number);
+ String numbers = "";
+ int slotId = SubscriptionManager.getSlotId(subId);
// retrieve the list of emergency numbers
// check read-write ecclist property first
- String numbers = SystemProperties.get("ril.ecclist");
+ String ecclist = (slotId == 0) ? "ril.ecclist" : ("ril.ecclist" + slotId);
+
+ numbers = SystemProperties.get(ecclist);
+
if (TextUtils.isEmpty(numbers)) {
// then read-only ecclist property since old RIL only uses this
numbers = SystemProperties.get("ro.ril.ecclist");
@@ -1742,15 +1876,29 @@
/**
* Checks if a given number is an emergency number for the country that the user is in.
- * @param context the specific context which the number should be checked against
- * @param number the number to look up.
*
+ * @param number the number to look up.
+ * @param context the specific context which the number should be checked against
* @return true if the specified number is an emergency number for the country the user
* is currently in.
*/
public static boolean isLocalEmergencyNumber(Context context, String number) {
- return isLocalEmergencyNumberInternal(context,
- number,
+ return isLocalEmergencyNumber(context, getDefaultVoiceSubId(), number);
+ }
+
+ /**
+ * Checks if a given number is an emergency number for the country that the user is in.
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @param context the specific context which the number should be checked against
+ * @return true if the specified number is an emergency number for the country the user
+ * is currently in.
+ * @hide
+ */
+ public static boolean isLocalEmergencyNumber(Context context, long subId, String number) {
+ return isLocalEmergencyNumberInternal(subId, number,
+ context,
true /* useExactMatch */);
}
@@ -1767,9 +1915,9 @@
* This method is intended for internal use by the phone app when
* deciding whether to allow ACTION_CALL intents from 3rd party apps
* (where we're required to *not* allow emergency calls to be placed.)
- * @param context the specific context which the number should be checked against
- * @param number the number to look up.
*
+ * @param number the number to look up.
+ * @param context the specific context which the number should be checked against
* @return true if the specified number is an emergency number for a local country, based on the
* CountryDetector.
*
@@ -1777,16 +1925,44 @@
* @hide
*/
public static boolean isPotentialLocalEmergencyNumber(Context context, String number) {
- return isLocalEmergencyNumberInternal(context,
- number,
+ return isPotentialLocalEmergencyNumber(context, getDefaultVoiceSubId(), number);
+ }
+
+ /**
+ * Checks if a given number might *potentially* result in a call to an
+ * emergency service, for the country that the user is in. The current
+ * country is determined using the CountryDetector.
+ *
+ * Specifically, this method will return true if the specified number
+ * is an emergency number in the current country, *or* if the number
+ * simply starts with the same digits as any emergency number for the
+ * current country.
+ *
+ * This method is intended for internal use by the phone app when
+ * deciding whether to allow ACTION_CALL intents from 3rd party apps
+ * (where we're required to *not* allow emergency calls to be placed.)
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @param context the specific context which the number should be checked against
+ * @return true if the specified number is an emergency number for a local country, based on the
+ * CountryDetector.
+ *
+ * @hide
+ */
+ public static boolean isPotentialLocalEmergencyNumber(Context context, long subId,
+ String number) {
+ return isLocalEmergencyNumberInternal(subId, number,
+ context,
false /* useExactMatch */);
}
/**
* Helper function for isLocalEmergencyNumber() and
* isPotentialLocalEmergencyNumber().
- * @param context the specific context which the number should be checked against
+ *
* @param number the number to look up.
+ * @param context the specific context which the number should be checked against
* @param useExactMatch if true, consider a number to be an emergency
* number only if it *exactly* matches a number listed in
* the RIL / SIM. If false, a number is considered to be an
@@ -1797,9 +1973,34 @@
* local country, based on the CountryDetector.
*
* @see android.location.CountryDetector
+ * @hide
*/
- private static boolean isLocalEmergencyNumberInternal(Context context,
- String number,
+ private static boolean isLocalEmergencyNumberInternal(String number,
+ Context context,
+ boolean useExactMatch) {
+ return isLocalEmergencyNumberInternal(getDefaultVoiceSubId(), number, context,
+ useExactMatch);
+ }
+
+ /**
+ * Helper function for isLocalEmergencyNumber() and
+ * isPotentialLocalEmergencyNumber().
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @param context the specific context which the number should be checked against
+ * @param useExactMatch if true, consider a number to be an emergency
+ * number only if it *exactly* matches a number listed in
+ * the RIL / SIM. If false, a number is considered to be an
+ * emergency number if it simply starts with the same digits
+ * as any of the emergency numbers listed in the RIL / SIM.
+ *
+ * @return true if the specified number is an emergency number for a
+ * local country, based on the CountryDetector.
+ * @hide
+ */
+ private static boolean isLocalEmergencyNumberInternal(long subId, String number,
+ Context context,
boolean useExactMatch) {
String countryIso;
CountryDetector detector = (CountryDetector) context.getSystemService(
@@ -1812,7 +2013,7 @@
Rlog.w(LOG_TAG, "No CountryDetector; falling back to countryIso based on locale: "
+ countryIso);
}
- return isEmergencyNumberInternal(number, countryIso, useExactMatch);
+ return isEmergencyNumberInternal(subId, number, countryIso, useExactMatch);
}
/**
@@ -1826,10 +2027,26 @@
* to read the VM number.
*/
public static boolean isVoiceMailNumber(String number) {
+ return isVoiceMailNumber(SubscriptionManager.getDefaultSubId(), number);
+ }
+
+ /**
+ * isVoiceMailNumber: checks a given number against the voicemail
+ * number provided by the RIL and SIM card. The caller must have
+ * the READ_PHONE_STATE credential.
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @return true if the number is in the list of voicemail. False
+ * otherwise, including if the caller does not have the permission
+ * to read the VM number.
+ * @hide
+ */
+ public static boolean isVoiceMailNumber(long subId, String number) {
String vmNumber;
try {
- vmNumber = TelephonyManager.getDefault().getVoiceMailNumber();
+ vmNumber = TelephonyManager.getDefault().getVoiceMailNumber(subId);
} catch (SecurityException ex) {
return false;
}
@@ -2561,5 +2778,11 @@
return true;
}
+ /**
+ * Returns Default voice subscription Id.
+ */
+ private static long getDefaultVoiceSubId() {
+ return SubscriptionManager.getDefaultVoiceSubId();
+ }
//==== End of utility methods used only in compareStrictly() =====
}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 59ec6f5..c8c3063 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -20,11 +20,13 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
import android.telephony.CellLocation;
import android.telephony.CellInfo;
+import android.telephony.VoLteServiceState;
import android.telephony.Rlog;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.SubscriptionManager;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
@@ -48,6 +50,7 @@
* appropriate LISTEN_ flags.
*/
public class PhoneStateListener {
+ private static final String TAG = "PhoneStateListener";
/**
* Stop listening for updates.
@@ -200,18 +203,42 @@
*/
public static final int LISTEN_DATA_CONNECTION_REAL_TIME_INFO = 0x00002000;
+ /**
+ * Listen for changes to LTE network state
+ *
+ * @see #onLteNetworkStateChanged
+ * @hide
+ */
+ public static final int LISTEN_VOLTE_STATE = 0x00004000;
+
+ /*
+ * Subscription used to listen to the phone state changes
+ * @hide
+ */
+ /** @hide */
+ protected long mSubId = 0;
+
private final Handler mHandler;
public PhoneStateListener() {
- this(Looper.myLooper());
+ this(SubscriptionManager.DEFAULT_SUB_ID, Looper.myLooper());
+ }
+
+ /**
+ * @hide
+ */
+ public PhoneStateListener(long subId) {
+ this(subId, Looper.myLooper());
}
/** @hide */
- public PhoneStateListener(Looper looper) {
+ public PhoneStateListener(long subId, Looper looper) {
+ Rlog.d(TAG, "ctor: subId=" + subId + " looper=" + looper);
+ mSubId = subId;
mHandler = new Handler(looper) {
public void handleMessage(Message msg) {
- //Rlog.d("TelephonyRegistry", "what=0x" + Integer.toHexString(msg.what)
- // + " msg=" + msg);
+ Rlog.d(TAG, "mSubId=" + mSubId + " what=0x" + Integer.toHexString(msg.what)
+ + " msg=" + msg);
switch (msg.what) {
case LISTEN_SERVICE_STATE:
PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);
@@ -258,6 +285,9 @@
PhoneStateListener.this.onDataConnectionRealTimeInfoChanged(
(DataConnectionRealTimeInfo)msg.obj);
break;
+ case LISTEN_VOLTE_STATE:
+ PhoneStateListener.this.onVoLteServiceStateChanged((VoLteServiceState)msg.obj);
+ break;
}
}
};
@@ -417,6 +447,15 @@
}
/**
+ * Callback invoked when the service state of LTE network
+ * related to the VoLTE service has changed.
+ * @param stateInfo is the current LTE network information
+ * @hide
+ */
+ public void onVoLteServiceStateChanged(VoLteServiceState stateInfo) {
+ }
+
+ /**
* The callback methods need to be called on the handler thread where
* this object was created. If the binder did that for us it'd be nice.
*/
@@ -484,5 +523,9 @@
Message.obtain(mHandler, LISTEN_DATA_CONNECTION_REAL_TIME_INFO, 0, 0,
dcRtInfo).sendToTarget();
}
+
+ public void onVoLteServiceStateChanged(VoLteServiceState lteState) {
+ Message.obtain(mHandler, LISTEN_VOLTE_STATE, 0, 0, lteState).sendToTarget();
+ }
};
}
diff --git a/telephony/java/android/telephony/SubInfoRecord.aidl b/telephony/java/android/telephony/SubInfoRecord.aidl
new file mode 100755
index 0000000..a2de676
--- /dev/null
+++ b/telephony/java/android/telephony/SubInfoRecord.aidl
@@ -0,0 +1,19 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable SubInfoRecord;
diff --git a/telephony/java/android/telephony/SubInfoRecord.java b/telephony/java/android/telephony/SubInfoRecord.java
new file mode 100644
index 0000000..670def7
--- /dev/null
+++ b/telephony/java/android/telephony/SubInfoRecord.java
@@ -0,0 +1,108 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A parcelable holder class of byte[] for ISms aidl implementation
+ * @hide
+ */
+
+public class SubInfoRecord implements Parcelable {
+
+ public long mSubId;
+ public String mIccId;
+ public int mSlotId;
+ public String mDisplayName;
+ public int mNameSource;
+ public int mColor;
+ public String mNumber;
+ public int mDispalyNumberFormat;
+ public int mDataRoaming;
+ public int[] mSimIconRes;
+
+ public SubInfoRecord() {
+ this.mSubId = -1;
+ this.mIccId = "";
+ this.mSlotId = -1;
+ this.mDisplayName = "";
+ this.mNameSource = 0;
+ this.mColor = 0;
+ this.mNumber = "";
+ this.mDispalyNumberFormat = 0;
+ this.mDataRoaming = 0;
+ this.mSimIconRes = new int[2];
+ }
+
+
+ public SubInfoRecord(long subId, String iccId, int slotId, String displayname, int nameSource,
+ int mColor, String mNumber, int displayFormat, int roaming, int[] iconRes) {
+ this.mSubId = subId;
+ this.mIccId = iccId;
+ this.mSlotId = slotId;
+ this.mDisplayName = displayname;
+ this.mNameSource = nameSource;
+ this.mColor = mColor;
+ this.mNumber = mNumber;
+ this.mDispalyNumberFormat = displayFormat;
+ this.mDataRoaming = roaming;
+ this.mSimIconRes = iconRes;
+ }
+
+ public static final Parcelable.Creator<SubInfoRecord> CREATOR = new Parcelable.Creator<SubInfoRecord>() {
+ public SubInfoRecord createFromParcel(Parcel source) {
+ long mSubId = source.readLong();
+ String mIccId = source.readString();
+ int mSlotId = source.readInt();
+ String mDisplayName = source.readString();
+ int mNameSource = source.readInt();
+ int mColor = source.readInt();
+ String mNumber = source.readString();
+ int mDispalyNumberFormat = source.readInt();
+ int mDataRoaming = source.readInt();
+ int[] iconRes = new int[2];
+ source.readIntArray(iconRes);
+
+ return new SubInfoRecord(mSubId, mIccId, mSlotId, mDisplayName, mNameSource, mColor, mNumber,
+ mDispalyNumberFormat, mDataRoaming, iconRes);
+ }
+
+ public SubInfoRecord[] newArray(int size) {
+ return new SubInfoRecord[size];
+ }
+ };
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mSubId);
+ dest.writeString(mIccId);
+ dest.writeInt(mSlotId);
+ dest.writeString(mDisplayName);
+ dest.writeInt(mNameSource);
+ dest.writeInt(mColor);
+ dest.writeString(mNumber);
+ dest.writeInt(mDispalyNumberFormat);
+ dest.writeInt(mDataRoaming);
+ dest.writeIntArray(mSimIconRes);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
new file mode 100644
index 0000000..859a890
--- /dev/null
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -0,0 +1,708 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.telephony;
+
+import static android.Manifest.permission.READ_PHONE_STATE;
+
+import android.app.ActivityManagerNative;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.os.UserHandle;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.telephony.Rlog;
+import android.os.ServiceManager;
+import android.os.RemoteException;
+
+import com.android.internal.telephony.ISub;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyIntents;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map.Entry;
+
+/**
+ *@hide
+ */
+public class SubscriptionManager implements BaseColumns {
+ private static final String LOG_TAG = "SUB";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ // An invalid subscription identifier
+ public static final long INVALID_SUB_ID = Long.MAX_VALUE;
+
+ // The default subscription identifier
+ public static final long DEFAULT_SUB_ID = Long.MAX_VALUE - 1;
+
+ public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+
+ public static final int DEFAULT_INT_VALUE = -100;
+
+ public static final String DEFAULT_STRING_VALUE = "N/A";
+
+ public static final int EXTRA_VALUE_NEW_SIM = 1;
+ public static final int EXTRA_VALUE_REMOVE_SIM = 2;
+ public static final int EXTRA_VALUE_REPOSITION_SIM = 3;
+ public static final int EXTRA_VALUE_NOCHANGE = 4;
+
+ public static final String INTENT_KEY_DETECT_STATUS = "simDetectStatus";
+ public static final String INTENT_KEY_SIM_COUNT = "simCount";
+ public static final String INTENT_KEY_NEW_SIM_SLOT = "newSIMSlot";
+ public static final String INTENT_KEY_NEW_SIM_STATUS = "newSIMStatus";
+
+ /**
+ * The ICC ID of a SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String ICC_ID = "icc_id";
+
+ /**
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String SIM_ID = "sim_id";
+
+ public static final int SIM_NOT_INSERTED = -1;
+
+ /**
+ * The display name of a SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String DISPLAY_NAME = "display_name";
+
+ public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName;
+
+ /**
+ * The display name source of a SIM.
+ * <P>Type: INT (int)</P>
+ */
+ public static final String NAME_SOURCE = "name_source";
+
+ public static final int DEFAULT_SOURCE = 0;
+
+ public static final int SIM_SOURCE = 1;
+
+ public static final int USER_INPUT = 2;
+
+ /**
+ * The color of a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String COLOR = "color";
+
+ public static final int COLOR_1 = 0;
+
+ public static final int COLOR_2 = 1;
+
+ public static final int COLOR_3 = 2;
+
+ public static final int COLOR_4 = 3;
+
+ public static final int COLOR_DEFAULT = COLOR_1;
+
+ /**
+ * The phone number of a SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String NUMBER = "number";
+
+ /**
+ * The number display format of a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
+
+ public static final int DISPALY_NUMBER_NONE = 0;
+
+ public static final int DISPLAY_NUMBER_FIRST = 1;
+
+ public static final int DISPLAY_NUMBER_LAST = 2;
+
+ public static final int DISLPAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
+
+ /**
+ * Permission for data roaming of a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String DATA_ROAMING = "data_roaming";
+
+ public static final int DATA_ROAMING_ENABLE = 1;
+
+ public static final int DATA_ROAMING_DISABLE = 0;
+
+ public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
+
+ private static final int RES_TYPE_BACKGROUND_DARK = 0;
+
+ private static final int RES_TYPE_BACKGROUND_LIGHT = 1;
+
+ private static final int[] sSimBackgroundDarkRes = setSimResource(RES_TYPE_BACKGROUND_DARK);
+
+ private static final int[] sSimBackgroundLightRes = setSimResource(RES_TYPE_BACKGROUND_LIGHT);
+
+ private static HashMap<Integer, Long> mSimInfo = new HashMap<Integer, Long>();
+
+ public SubscriptionManager() {
+ if (DBG) logd("SubscriptionManager created");
+ }
+
+ /**
+ * Get the SubInfoRecord according to an index
+ * @param context Context provided by caller
+ * @param subId The unique SubInfoRecord index in database
+ * @return SubInfoRecord, maybe null
+ */
+ public static SubInfoRecord getSubInfoUsingSubId(Context context, long subId) {
+ if (VDBG) logd("[getSubInfoUsingSubIdx]+ subId:" + subId);
+ if (subId <= 0) {
+ if (VDBG) logd("[getSubInfoUsingSubIdx]- subId <= 0");
+ return null;
+ }
+
+ SubInfoRecord subInfo = null;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ subInfo = iSub.getSubInfoUsingSubId(subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return subInfo;
+
+ }
+
+ /**
+ * Get the SubInfoRecord according to an IccId
+ * @param context Context provided by caller
+ * @param iccId the IccId of SIM card
+ * @return SubInfoRecord, maybe null
+ */
+ public static List<SubInfoRecord> getSubInfoUsingIccId(Context context, String iccId) {
+ if (VDBG) logd("[getSubInfoUsingIccId]+ iccId=" + iccId);
+ if (iccId == null) {
+ logd("[getSubInfoUsingIccId]- null iccid");
+ return null;
+ }
+
+ List<SubInfoRecord> result = null;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getSubInfoUsingIccId(iccId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+ }
+
+ /**
+ * Get the SubInfoRecord according to slotId
+ * @param context Context provided by caller
+ * @param slotId the slot which the SIM is inserted
+ * @return SubInfoRecord, maybe null
+ */
+ public static List<SubInfoRecord> getSubInfoUsingSlotId(Context context, int slotId) {
+ if (VDBG) logd("[getSubInfoUsingSlotId]- slotId=" + slotId);
+ if (slotId < 0) {
+ logd("[getSubInfoUsingSlotId]- return null, slotId < 0");
+ return null;
+ }
+
+ List<SubInfoRecord> result = null;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getSubInfoUsingSlotId(slotId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+ }
+
+ /**
+ * Get all the SubInfoRecord(s) in subinfo database
+ * @param context Context provided by caller
+ * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before
+ */
+ public static List<SubInfoRecord> getAllSubInfoList(Context context) {
+ if (VDBG) logd("[getAllSubInfoList]+");
+
+ List<SubInfoRecord> result = null;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getAllSubInfoList();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+ }
+
+ /**
+ * Get the SubInfoRecord(s) of the currently inserted SIM(s)
+ * @param context Context provided by caller
+ * @return Array list of currently inserted SubInfoRecord(s)
+ */
+ public static List<SubInfoRecord> getActivatedSubInfoList(Context context) {
+ if (VDBG) logd("[getActivatedSubInfoList]+");
+
+ List<SubInfoRecord> result = null;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getActivatedSubInfoList();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+ }
+
+ /**
+ * Get the SUB count of all SUB(s) in subinfo database
+ * @param context Context provided by caller
+ * @return all SIM count in database, include what was inserted before
+ */
+ public static int getAllSubInfoCount(Context context) {
+ if (VDBG) logd("[getAllSubInfoCount]+");
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getAllSubInfoCount();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+ }
+
+ /**
+ * Add a new SubInfoRecord to subinfo database if needed
+ * @param context Context provided by caller
+ * @param iccId the IccId of the SIM card
+ * @param slotId the slot which the SIM is inserted
+ * @return the URL of the newly created row or the updated row
+ */
+ public static Uri addSubInfoRecord(Context context, String iccId, int slotId) {
+ if (VDBG) logd("[addSubInfoRecord]+ iccId:" + iccId + " slotId:" + slotId);
+ if (iccId == null) {
+ logd("[addSubInfoRecord]- null iccId");
+ }
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ // FIXME: This returns 1 on success, 0 on error should should we return it?
+ iSub.addSubInfoRecord(iccId, slotId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ // FIXME: Always returns null?
+ return null;
+
+ }
+
+ /**
+ * Set SIM color by simInfo index
+ * @param context Context provided by caller
+ * @param color the color of the SIM
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ public static int setColor(Context context, int color, long subId) {
+ if (VDBG) logd("[setColor]+ color:" + color + " subId:" + subId);
+ int size = sSimBackgroundDarkRes.length;
+ if (subId <= 0 || color < 0 || color >= size) {
+ logd("[setColor]- fail");
+ return -1;
+ }
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.setColor(color, subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Set display name by simInfo index
+ * @param context Context provided by caller
+ * @param displayName the display name of SIM card
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ public static int setDisplayName(Context context, String displayName, long subId) {
+ return setDisplayName(context, displayName, subId, -1);
+ }
+
+ /**
+ * Set display name by simInfo index with name source
+ * @param context Context provided by caller
+ * @param displayName the display name of SIM card
+ * @param subId the unique SubInfoRecord index in database
+ * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT
+ * @return the number of records updated
+ */
+ public static int setDisplayName(Context context, String displayName, long subId, long nameSource) {
+ if (VDBG) logd("[setDisplayName]+ displayName:" + displayName + " subId:" + subId + " nameSource:" + nameSource);
+ if (subId <= 0) {
+ logd("[setDisplayName]- fail");
+ return -1;
+ }
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.setDisplayNameUsingSrc(displayName, subId, nameSource);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Set phone number by subId
+ * @param context Context provided by caller
+ * @param number the phone number of the SIM
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ public static int setDispalyNumber(Context context, String number, long subId) {
+ if (VDBG) logd("[setDispalyNumber]+ number:" + number + " subId:" + subId);
+ if (number == null || subId <= 0) {
+ logd("[setDispalyNumber]- fail");
+ return -1;
+ }
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.setDispalyNumber(number, subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Set number display format. 0: none, 1: the first four digits, 2: the last four digits
+ * @param context Context provided by caller
+ * @param format the display format of phone number
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ public static int setDisplayNumberFormat(Context context, int format, long subId) {
+ if (VDBG) logd("[setDisplayNumberFormat]+ format:" + format + " subId:" + subId);
+ if (format < 0 || subId <= 0) {
+ logd("[setDisplayNumberFormat]- fail, return -1");
+ return -1;
+ }
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.setDisplayNumberFormat(format, subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Set data roaming by simInfo index
+ * @param context Context provided by caller
+ * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ public static int setDataRoaming(Context context, int roaming, long subId) {
+ if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId);
+ if (roaming < 0 || subId <= 0) {
+ logd("[setDataRoaming]- fail");
+ return -1;
+ }
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.setDataRoaming(roaming, subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+ }
+
+ public static int getSlotId(long subId) {
+ if (VDBG) logd("[getSlotId]+ subId:" + subId);
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getSlotId(subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+
+ }
+
+ public static long[] getSubId(int slotId) {
+ if (VDBG) logd("[getSubId]+ slotId:" + slotId);
+
+ long[] subId = null;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ subId = iSub.getSubId(slotId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return subId;
+ }
+
+ public static int getPhoneId(long subId) {
+ if (VDBG) logd("[getPhoneId]+ subId=" + subId);
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getPhoneId(subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ if (VDBG) logd("[getPhoneId]- phonId=" + result);
+ return result;
+
+ }
+
+ private static int[] setSimResource(int type) {
+ int[] simResource = null;
+
+ switch (type) {
+ case RES_TYPE_BACKGROUND_DARK:
+ simResource = new int[] {
+ com.android.internal.R.drawable.sim_dark_blue,
+ com.android.internal.R.drawable.sim_dark_orange,
+ com.android.internal.R.drawable.sim_dark_green,
+ com.android.internal.R.drawable.sim_dark_purple
+ };
+ break;
+ case RES_TYPE_BACKGROUND_LIGHT:
+ simResource = new int[] {
+ com.android.internal.R.drawable.sim_light_blue,
+ com.android.internal.R.drawable.sim_light_orange,
+ com.android.internal.R.drawable.sim_light_green,
+ com.android.internal.R.drawable.sim_light_purple
+ };
+ break;
+ }
+
+ return simResource;
+ }
+
+ private static void logd(String msg) {
+ Rlog.d(LOG_TAG, "[SubManager] " + msg);
+ }
+
+ public static long normalizeSubId(long subId) {
+ long retVal = (subId == DEFAULT_SUB_ID) ? getDefaultSubId() : subId;
+ Rlog.d(LOG_TAG, "[SubManager] normalizeSubId subId=" + retVal);
+ return retVal;
+ }
+
+ public static boolean validSubId(long subId) {
+ return (subId != DEFAULT_SUB_ID) && (subId != -1);
+ }
+
+ /**
+ * @return the "system" defaultSubId on a voice capable device this
+ * will be getDefaultVoiceSubId() and on a data only device it will be
+ * getDefaultDataSubId().
+ */
+ public static long getDefaultSubId() {
+ long subId = 1;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ subId = iSub.getDefaultSubId();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ if (VDBG) logd("getDefaultSubId=" + subId);
+ return subId;
+ }
+
+ public static long getDefaultVoiceSubId() {
+ long subId = 1;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ subId = iSub.getDefaultVoiceSubId();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ if (VDBG) logd("getDefaultSubId, sub id = " + subId);
+ return subId;
+ }
+
+ public static void setDefaultVoiceSubId(long subId) {
+ if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId);
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ iSub.setDefaultVoiceSubId(subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ }
+
+ public static long getPreferredSmsSubId() {
+ // FIXME add framework support to get the preferred sub
+ return getDefaultSubId();
+ }
+
+ public static long getPreferredDataSubId() {
+ // FIXME add framework support to get the preferred sub
+ return getDefaultSubId();
+ }
+
+ public static long getDefaultDataSubId() {
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ return iSub.getDefaultDataSubId();
+ } else {
+ return -1;
+ }
+ } catch (RemoteException ex) {
+ return -1;
+ }
+ }
+
+ public static void setDefaultDataSubId(long subId) {
+ if (VDBG) logd("setDataSubscription sub id = " + subId);
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ iSub.setDefaultDataSubId(subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ }
+
+ public static void clearSubInfo()
+ {
+ if (VDBG) logd("[clearSubInfo]+");
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ iSub.clearSubInfo();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return;
+ }
+
+ public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
+ long [] subId = SubscriptionManager.getSubId(phoneId);
+ if ((subId != null) && (subId.length >= 1)) {
+ if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId);
+ intent.putExtra(PhoneConstants.SLOT_KEY, phoneId); //FIXME: RENAME TO PHONE_ID_KEY ??
+ intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId[0]);
+ } else {
+ logd("putPhoneIdAndSubIdExtra: no valid subs");
+ }
+ }
+}
+
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ffa9a4e..50bbb1e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -16,7 +16,7 @@
package android.telephony;
-import android.annotation.PrivateApi;
+import android.annotation.SystemApi;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
@@ -86,6 +86,22 @@
private final Context mContext;
+ private static String multiSimConfig =
+ SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG);
+
+ /** Enum indicating multisim variants
+ * DSDS - Dual SIM Dual Standby
+ * DSDA - Dual SIM Dual Active
+ * TSTS - Triple SIM Triple Standby
+ **/
+ /** @hide */
+ public enum MultiSimVariants {
+ DSDS,
+ DSDA,
+ TSTS,
+ UNKNOWN
+ };
+
/** @hide */
public TelephonyManager(Context context) {
Context appContext = context.getApplicationContext();
@@ -114,11 +130,61 @@
return sInstance;
}
+
+ /**
+ * Returns the multi SIM variant
+ * Returns DSDS for Dual SIM Dual Standby
+ * Returns DSDA for Dual SIM Dual Active
+ * Returns TSTS for Triple SIM Triple Standby
+ * Returns UNKNOWN for others
+ */
+ /** {@hide} */
+ public MultiSimVariants getMultiSimConfiguration() {
+ String mSimConfig =
+ SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG);
+ if (mSimConfig.equals("dsds")) {
+ return MultiSimVariants.DSDS;
+ } else if (mSimConfig.equals("dsda")) {
+ return MultiSimVariants.DSDA;
+ } else if (mSimConfig.equals("tsts")) {
+ return MultiSimVariants.TSTS;
+ } else {
+ return MultiSimVariants.UNKNOWN;
+ }
+ }
+
+
+ /**
+ * Returns the number of phones available.
+ * Returns 1 for Single standby mode (Single SIM functionality)
+ * Returns 2 for Dual standby mode.(Dual SIM functionality)
+ */
+ /** {@hide} */
+ public int getPhoneCount() {
+ int phoneCount = 1;
+ switch (getMultiSimConfiguration()) {
+ case DSDS:
+ case DSDA:
+ phoneCount = PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
+ break;
+ case TSTS:
+ phoneCount = PhoneConstants.MAX_PHONE_COUNT_TRI_SIM;
+ break;
+ }
+ return phoneCount;
+ }
+
/** {@hide} */
public static TelephonyManager from(Context context) {
return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
}
+ /** {@hide} */
+ public boolean isMultiSimEnabled() {
+ return (multiSimConfig.equals("dsds") || multiSimConfig.equals("dsda") ||
+ multiSimConfig.equals("tsts"));
+ }
+
//
// Broadcast Intent actions
//
@@ -529,8 +595,23 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getDeviceId() {
+ return getDeviceId(getDefaultSim());
+ }
+
+ /**
+ * Returns the unique device ID of a subscription, for example, the IMEI for
+ * GSM and the MEID for CDMA phones. Return null if device ID is not available.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param slotId of which deviceID is returned
+ */
+ /** {@hide} */
+ public String getDeviceId(int slotId) {
+ long[] subId = SubscriptionManager.getSubId(slotId);
try {
- return getSubscriberInfo().getDeviceId();
+ return getSubscriberInfo().getDeviceIdUsingSubId(subId[0]);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -578,8 +659,23 @@
* @hide
*/
public void enableLocationUpdates() {
+ enableLocationUpdates(getDefaultSubscription());
+ }
+
+ /**
+ * Enables location update notifications for a subscription.
+ * {@link PhoneStateListener#onCellLocationChanged
+ * PhoneStateListener.onCellLocationChanged} will be called on location updates.
+ *
+ * <p>Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES
+ * CONTROL_LOCATION_UPDATES}
+ *
+ * @param subId for which the location updates are enabled
+ */
+ /** @hide */
+ public void enableLocationUpdates(long subId) {
try {
- getITelephony().enableLocationUpdates();
+ getITelephony().enableLocationUpdatesUsingSubId(subId);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -595,8 +691,13 @@
* @hide
*/
public void disableLocationUpdates() {
+ disableLocationUpdates(getDefaultSubscription());
+ }
+
+ /** @hide */
+ public void disableLocationUpdates(long subId) {
try {
- getITelephony().disableLocationUpdates();
+ getITelephony().disableLocationUpdatesUsingSubId(subId);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -644,22 +745,37 @@
* {@hide}
*/
public int getCurrentPhoneType() {
+ return getCurrentPhoneType(getDefaultSubscription());
+ }
+
+ /**
+ * Returns a constant indicating the device phone type for a subscription.
+ *
+ * @see #PHONE_TYPE_NONE
+ * @see #PHONE_TYPE_GSM
+ * @see #PHONE_TYPE_CDMA
+ *
+ * @param subId for which phone type is returned
+ */
+ /** {@hide} */
+ public int getCurrentPhoneType(long subId) {
+
try{
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.getActivePhoneType();
+ return telephony.getActivePhoneTypeUsingSubId(subId);
} else {
// This can happen when the ITelephony interface is not up yet.
- return getPhoneTypeFromProperty();
+ return getPhoneTypeFromProperty(subId);
}
} catch (RemoteException ex) {
// This shouldn't happen in the normal case, as a backup we
// read from the system property.
- return getPhoneTypeFromProperty();
+ return getPhoneTypeFromProperty(subId);
} catch (NullPointerException ex) {
// This shouldn't happen in the normal case, as a backup we
// read from the system property.
- return getPhoneTypeFromProperty();
+ return getPhoneTypeFromProperty(subId);
}
}
@@ -680,20 +796,35 @@
}
private int getPhoneTypeFromProperty() {
- int type =
- SystemProperties.getInt(TelephonyProperties.CURRENT_ACTIVE_PHONE,
- getPhoneTypeFromNetworkType());
- return type;
+ return getPhoneTypeFromProperty(getDefaultSubscription());
+ }
+
+ /** {@hide} */
+ private int getPhoneTypeFromProperty(long subId) {
+ String type =
+ getTelephonyProperty
+ (TelephonyProperties.CURRENT_ACTIVE_PHONE, subId, null);
+ if (type != null) {
+ return (Integer.parseInt(type));
+ } else {
+ return getPhoneTypeFromNetworkType(subId);
+ }
}
private int getPhoneTypeFromNetworkType() {
+ return getPhoneTypeFromNetworkType(getDefaultSubscription());
+ }
+
+ /** {@hide} */
+ private int getPhoneTypeFromNetworkType(long subId) {
// When the system property CURRENT_ACTIVE_PHONE, has not been set,
// use the system property for default network type.
// This is a fail safe, and can only happen at first boot.
- int mode = SystemProperties.getInt("ro.telephony.default_network", -1);
- if (mode == -1)
- return PHONE_TYPE_NONE;
- return getPhoneType(mode);
+ String mode = getTelephonyProperty("ro.telephony.default_network", subId, null);
+ if (mode != null) {
+ return TelephonyManager.getPhoneType(Integer.parseInt(mode));
+ }
+ return TelephonyManager.PHONE_TYPE_NONE;
}
/**
@@ -828,7 +959,23 @@
* on a CDMA network).
*/
public String getNetworkOperatorName() {
- return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ALPHA);
+ return getNetworkOperatorName(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the alphabetic name of current registered operator
+ * for a particular subscription.
+ * <p>
+ * Availability: Only when user is registered to a network. Result may be
+ * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
+ * on a CDMA network).
+ * @param subId
+ */
+ /** {@hide} */
+ public String getNetworkOperatorName(long subId) {
+
+ return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
+ subId, "");
}
/**
@@ -839,17 +986,48 @@
* on a CDMA network).
*/
public String getNetworkOperator() {
- return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC);
+ return getNetworkOperator(getDefaultSubscription());
}
/**
+ * Returns the numeric name (MCC+MNC) of current registered operator
+ * for a particular subscription.
+ * <p>
+ * Availability: Only when user is registered to a network. Result may be
+ * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
+ * on a CDMA network).
+ *
+ * @param subId
+ */
+ /** {@hide} */
+ public String getNetworkOperator(long subId) {
+
+ return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC,
+ subId, "");
+ }
+
+ /**
* Returns true if the device is considered roaming on the current
* network, for GSM purposes.
* <p>
* Availability: Only when user registered to a network.
*/
public boolean isNetworkRoaming() {
- return "true".equals(SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
+ return isNetworkRoaming(getDefaultSubscription());
+ }
+
+ /**
+ * Returns true if the device is considered roaming on the current
+ * network for a subscription.
+ * <p>
+ * Availability: Only when user registered to a network.
+ *
+ * @param subId
+ */
+ /** {@hide} */
+ public boolean isNetworkRoaming(long subId) {
+ return "true".equals(getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
+ subId, null));
}
/**
@@ -861,7 +1039,23 @@
* on a CDMA network).
*/
public String getNetworkCountryIso() {
- return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY);
+ return getNetworkCountryIso(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the ISO country code equivalent of the current registered
+ * operator's MCC (Mobile Country Code) of a subscription.
+ * <p>
+ * Availability: Only when user is registered to a network. Result may be
+ * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
+ * on a CDMA network).
+ *
+ * @param subId for which Network CountryIso is returned
+ */
+ /** {@hide} */
+ public String getNetworkCountryIso(long subId) {
+ return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY,
+ subId, "");
}
/** Network type is unknown */
@@ -908,6 +1102,49 @@
/**
* Returns a constant indicating the radio technology (network type)
+ * currently in use on the device for a subscription.
+ * @return the network type
+ *
+ * @param subId for which network type is returned
+ *
+ * @see #NETWORK_TYPE_UNKNOWN
+ * @see #NETWORK_TYPE_GPRS
+ * @see #NETWORK_TYPE_EDGE
+ * @see #NETWORK_TYPE_UMTS
+ * @see #NETWORK_TYPE_HSDPA
+ * @see #NETWORK_TYPE_HSUPA
+ * @see #NETWORK_TYPE_HSPA
+ * @see #NETWORK_TYPE_CDMA
+ * @see #NETWORK_TYPE_EVDO_0
+ * @see #NETWORK_TYPE_EVDO_A
+ * @see #NETWORK_TYPE_EVDO_B
+ * @see #NETWORK_TYPE_1xRTT
+ * @see #NETWORK_TYPE_IDEN
+ * @see #NETWORK_TYPE_LTE
+ * @see #NETWORK_TYPE_EHRPD
+ * @see #NETWORK_TYPE_HSPAP
+ */
+ /** {@hide} */
+ public int getNetworkType(long subId) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getNetworkTypeUsingSubId(subId);
+ } else {
+ // This can happen when the ITelephony interface is not up yet.
+ return NETWORK_TYPE_UNKNOWN;
+ }
+ } catch(RemoteException ex) {
+ // This shouldn't happen in the normal case
+ return NETWORK_TYPE_UNKNOWN;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return NETWORK_TYPE_UNKNOWN;
+ }
+ }
+
+ /**
+ * Returns a constant indicating the radio technology (network type)
* currently in use on the device for data transmission.
* @return the network type
*
@@ -931,10 +1168,22 @@
* @hide
*/
public int getDataNetworkType() {
+ return getDataNetworkType(getDefaultSubscription());
+ }
+
+ /**
+ * Returns a constant indicating the radio technology (network type)
+ * currently in use on the device for data transmission for a subscription
+ * @return the network type
+ *
+ * @param subId for which network type is returned
+ */
+ /** {@hide} */
+ public int getDataNetworkType(long subId) {
try{
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.getDataNetworkType();
+ return telephony.getDataNetworkTypeUsingSubId(subId);
} else {
// This can happen when the ITelephony interface is not up yet.
return NETWORK_TYPE_UNKNOWN;
@@ -954,10 +1203,19 @@
* @hide
*/
public int getVoiceNetworkType() {
+ return getVoiceNetworkType(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the NETWORK_TYPE_xxxx for voice for a subId
+ *
+ */
+ /** {@hide} */
+ public int getVoiceNetworkType(long subId) {
try{
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.getVoiceNetworkType();
+ return telephony.getVoiceNetworkTypeUsingSubId(subId);
} else {
// This can happen when the ITelephony interface is not up yet.
return NETWORK_TYPE_UNKNOWN;
@@ -1023,6 +1281,13 @@
return getNetworkTypeName(getNetworkType());
}
+ /**
+ * Returns a string representation of the radio technology (network type)
+ * currently in use on the device.
+ * @param subId for which network type is returned
+ * @return the name of the radio technology
+ *
+ */
/** {@hide} */
public static String getNetworkTypeName(int type) {
switch (type) {
@@ -1093,8 +1358,20 @@
* @return true if a ICC card is present
*/
public boolean hasIccCard() {
+ return hasIccCard(getDefaultSim());
+ }
+
+ /**
+ * @return true if a ICC card is present for a subscription
+ *
+ * @param slotId for which icc card presence is checked
+ */
+ /** {@hide} */
+ // FIXME Input argument slotId should be of type int
+ public boolean hasIccCard(long slotId) {
+
try {
- return getITelephony().hasIccCard();
+ return getITelephony().hasIccCardUsingSlotId(slotId);
} catch (RemoteException ex) {
// Assume no ICC card if remote exception which shouldn't happen
return false;
@@ -1117,7 +1394,33 @@
* @see #SIM_STATE_CARD_IO_ERROR
*/
public int getSimState() {
- String prop = SystemProperties.get(TelephonyProperties.PROPERTY_SIM_STATE);
+ return getSimState(getDefaultSim());
+ }
+
+ /**
+ * Returns a constant indicating the state of the
+ * device SIM card in a slot.
+ *
+ * @param slotId
+ *
+ * @see #SIM_STATE_UNKNOWN
+ * @see #SIM_STATE_ABSENT
+ * @see #SIM_STATE_PIN_REQUIRED
+ * @see #SIM_STATE_PUK_REQUIRED
+ * @see #SIM_STATE_NETWORK_LOCKED
+ * @see #SIM_STATE_READY
+ */
+ /** {@hide} */
+ // FIXME the argument to pass is subId ??
+ public int getSimState(int slotId) {
+ long[] subId = SubscriptionManager.getSubId(slotId);
+ if (subId == null) {
+ return SIM_STATE_ABSENT;
+ }
+ // FIXME Do not use a property to determine SIM_STATE, call
+ // appropriate method on some object.
+ String prop =
+ getTelephonyProperty(TelephonyProperties.PROPERTY_SIM_STATE, subId[0], "");
if ("ABSENT".equals(prop)) {
return SIM_STATE_ABSENT;
}
@@ -1150,7 +1453,27 @@
* @see #getSimState
*/
public String getSimOperator() {
- return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC);
+ long subId = getDefaultSubscription();
+ Rlog.d(TAG, "getSimOperator(): default subId=" + subId);
+ return getSimOperator(subId);
+ }
+
+ /**
+ * Returns the MCC+MNC (mobile country code + mobile network code) of the
+ * provider of the SIM for a particular subscription. 5 or 6 decimal digits.
+ * <p>
+ * Availability: SIM state must be {@link #SIM_STATE_READY}
+ *
+ * @see #getSimState
+ *
+ * @param subId for which SimOperator is returned
+ */
+ /** {@hide} */
+ public String getSimOperator(long subId) {
+ String operator = getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC,
+ subId, "");
+ Rlog.d(TAG, "getSimOperator: subId=" + subId + " operator=" + operator);
+ return operator;
}
/**
@@ -1161,14 +1484,40 @@
* @see #getSimState
*/
public String getSimOperatorName() {
- return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA);
+ return getSimOperatorName(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the Service Provider Name (SPN).
+ * <p>
+ * Availability: SIM state must be {@link #SIM_STATE_READY}
+ *
+ * @see #getSimState
+ *
+ * @param subId for which SimOperatorName is returned
+ */
+ /** {@hide} */
+ public String getSimOperatorName(long subId) {
+ return getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA,
+ subId, "");
}
/**
* Returns the ISO country code equivalent for the SIM provider's country code.
*/
public String getSimCountryIso() {
- return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY);
+ return getSimCountryIso(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the ISO country code equivalent for the SIM provider's country code.
+ *
+ * @param subId for which SimCountryIso is returned
+ */
+ /** {@hide} */
+ public String getSimCountryIso(long subId) {
+ return getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
+ subId, "");
}
/**
@@ -1179,8 +1528,21 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getSimSerialNumber() {
+ return getSimSerialNumber(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the serial number for the given subscription, if applicable. Return null if it is
+ * unavailable.
+ * <p>
+ * @param subId for which Sim Serial number is returned
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ */
+ /** {@hide} */
+ public String getSimSerialNumber(long subId) {
try {
- return getSubscriberInfo().getIccSerialNumber();
+ return getSubscriberInfo().getIccSerialNumberUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1200,8 +1562,23 @@
* @hide
*/
public int getLteOnCdmaMode() {
+ return getLteOnCdmaMode(getDefaultSubscription());
+ }
+
+ /**
+ * Return if the current radio is LTE on CDMA for Subscription. This
+ * is a tri-state return value as for a period of time
+ * the mode may be unknown.
+ *
+ * @param subId for which radio is LTE on CDMA is returned
+ * @return {@link PhoneConstants#LTE_ON_CDMA_UNKNOWN}, {@link PhoneConstants#LTE_ON_CDMA_FALSE}
+ * or {@link PhoneConstants#LTE_ON_CDMA_TRUE}
+ *
+ */
+ /** {@hide} */
+ public int getLteOnCdmaMode(long subId) {
try {
- return getITelephony().getLteOnCdmaMode();
+ return getITelephony().getLteOnCdmaModeUsingSubId(subId);
} catch (RemoteException ex) {
// Assume no ICC card if remote exception which shouldn't happen
return PhoneConstants.LTE_ON_CDMA_UNKNOWN;
@@ -1225,8 +1602,23 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getSubscriberId() {
+ return getSubscriberId(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the unique subscriber ID, for example, the IMSI for a GSM phone
+ * for a subscription.
+ * Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param subId whose subscriber id is returned
+ */
+ /** {@hide} */
+ public String getSubscriberId(long subId) {
try {
- return getSubscriberInfo().getSubscriberId();
+ return getSubscriberInfo().getSubscriberIdUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1254,6 +1646,27 @@
}
/**
+ * Returns the Group Identifier Level1 for a GSM phone for a particular subscription.
+ * Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param subscription whose subscriber id is returned
+ */
+ /** {@hide} */
+ public String getGroupIdLevel1(long subId) {
+ try {
+ return getSubscriberInfo().getGroupIdLevel1UsingSubId(subId);
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return null;
+ }
+ }
+
+ /**
* Returns the phone number string for line 1, for example, the MSISDN
* for a GSM phone. Return null if it is unavailable.
* <p>
@@ -1261,8 +1674,22 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getLine1Number() {
+ return getLine1Number(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the phone number string for line 1, for example, the MSISDN
+ * for a GSM phone for a particular subscription. Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param subId whose phone number for line 1 is returned
+ */
+ /** {@hide} */
+ public String getLine1Number(long subId) {
try {
- return getSubscriberInfo().getLine1Number();
+ return getSubscriberInfo().getLine1NumberUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1281,8 +1708,23 @@
* nobody seems to call this.
*/
public String getLine1AlphaTag() {
+ return getLine1AlphaTag(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the alphabetic identifier associated with the line 1 number
+ * for a subscription.
+ * Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * @param subId whose alphabetic identifier associated with line 1 is returned
+ * nobody seems to call this.
+ */
+ /** {@hide} */
+ public String getLine1AlphaTag(long subId) {
try {
- return getSubscriberInfo().getLine1AlphaTag();
+ return getSubscriberInfo().getLine1AlphaTagUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1301,8 +1743,22 @@
* @hide
*/
public String getMsisdn() {
+ return getMsisdn(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the MSISDN string.
+ * for a GSM phone. Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param subId for which msisdn is returned
+ */
+ /** {@hide} */
+ public String getMsisdn(long subId) {
try {
- return getSubscriberInfo().getMsisdn();
+ return getSubscriberInfo().getMsisdnUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1318,8 +1774,21 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getVoiceMailNumber() {
+ return getVoiceMailNumber(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the voice mail number for a subscription.
+ * Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * @param subId whose voice mail number is returned
+ */
+ /** {@hide} */
+ public String getVoiceMailNumber(long subId) {
try {
- return getSubscriberInfo().getVoiceMailNumber();
+ return getSubscriberInfo().getVoiceMailNumberUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1337,8 +1806,21 @@
* @hide
*/
public String getCompleteVoiceMailNumber() {
+ return getCompleteVoiceMailNumber(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the complete voice mail number. Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#CALL_PRIVILEGED CALL_PRIVILEGED}
+ *
+ * @param subId
+ */
+ /** {@hide} */
+ public String getCompleteVoiceMailNumber(long subId) {
try {
- return getSubscriberInfo().getCompleteVoiceMailNumber();
+ return getSubscriberInfo().getCompleteVoiceMailNumberUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1355,8 +1837,20 @@
* @hide
*/
public int getVoiceMessageCount() {
+ return getVoiceMessageCount(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the voice mail count for a subscription. Return 0 if unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * @param subId whose voice message count is returned
+ */
+ /** {@hide} */
+ public int getVoiceMessageCount(long subId) {
try {
- return getITelephony().getVoiceMessageCount();
+ return getITelephony().getVoiceMessageCountUsingSubId(subId);
} catch (RemoteException ex) {
return 0;
} catch (NullPointerException ex) {
@@ -1373,8 +1867,22 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getVoiceMailAlphaTag() {
+ return getVoiceMailAlphaTag(getDefaultSubscription());
+ }
+
+ /**
+ * Retrieves the alphabetic identifier associated with the voice
+ * mail number for a subscription.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * @param subId whose alphabetic identifier associated with the
+ * voice mail number is returned
+ */
+ /** {@hide} */
+ public String getVoiceMailAlphaTag(long subId) {
try {
- return getSubscriberInfo().getVoiceMailAlphaTag();
+ return getSubscriberInfo().getVoiceMailAlphaTagUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1437,7 +1945,6 @@
return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
}
-
/** Device call state: No activity. */
public static final int CALL_STATE_IDLE = 0;
/** Device call state: Ringing. A new call arrived and is
@@ -1453,8 +1960,19 @@
* Returns a constant indicating the call state (cellular) on the device.
*/
public int getCallState() {
+ return getCallState(getDefaultSubscription());
+ }
+
+ /**
+ * Returns a constant indicating the call state (cellular) on the device
+ * for a subscription.
+ *
+ * @param subId whose call state is returned
+ */
+ /** {@hide} */
+ public int getCallState(long subId) {
try {
- return getITelephony().getCallState();
+ return getITelephony().getCallStateUsingSubId(subId);
} catch (RemoteException ex) {
// the phone process is restarting.
return CALL_STATE_IDLE;
@@ -1575,8 +2093,8 @@
public void listen(PhoneStateListener listener, int events) {
String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>";
try {
- Boolean notifyNow = true;
- sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);
+ Boolean notifyNow = (getITelephony() != null);
+ sRegistry.listenUsingSubId(listener.mSubId, pkgForDebug, listener.callback, events, notifyNow);
} catch (RemoteException ex) {
// system process dead
} catch (NullPointerException ex) {
@@ -1590,8 +2108,16 @@
* @hide
*/
public int getCdmaEriIconIndex() {
+ return getCdmaEriIconIndex(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the CDMA ERI icon index to display for a subscription
+ */
+ /** {@hide} */
+ public int getCdmaEriIconIndex(long subId) {
try {
- return getITelephony().getCdmaEriIconIndex();
+ return getITelephony().getCdmaEriIconIndexUsingSubId(subId);
} catch (RemoteException ex) {
// the phone process is restarting.
return -1;
@@ -1608,8 +2134,18 @@
* @hide
*/
public int getCdmaEriIconMode() {
+ return getCdmaEriIconMode(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the CDMA ERI icon mode for a subscription.
+ * 0 - ON
+ * 1 - FLASHING
+ */
+ /** {@hide} */
+ public int getCdmaEriIconMode(long subId) {
try {
- return getITelephony().getCdmaEriIconMode();
+ return getITelephony().getCdmaEriIconModeUsingSubId(subId);
} catch (RemoteException ex) {
// the phone process is restarting.
return -1;
@@ -1624,8 +2160,17 @@
* @hide
*/
public String getCdmaEriText() {
+ return getCdmaEriText(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the CDMA ERI text, of a subscription
+ *
+ */
+ /** {@hide} */
+ public String getCdmaEriText(long subId) {
try {
- return getITelephony().getCdmaEriText();
+ return getITelephony().getCdmaEriTextUsingSubId(subId);
} catch (RemoteException ex) {
// the phone process is restarting.
return null;
@@ -1924,6 +2469,286 @@
}
/**
+ * Returns Default subscription.
+ */
+ private static long getDefaultSubscription() {
+ return SubscriptionManager.getDefaultSubId();
+ }
+
+ /** {@hide} */
+ public int getDefaultSim() {
+ //TODO Need to get it from Telephony Devcontroller
+ return 0;
+ }
+
+ /**
+ * Sets the telephony property with the value specified.
+ *
+ * @hide
+ */
+ public static void setTelephonyProperty(String property, long subId, String value) {
+ String propVal = "";
+ String p[] = null;
+ String prop = SystemProperties.get(property);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+
+ if (value == null) {
+ value = "";
+ }
+
+ if (prop != null) {
+ p = prop.split(",");
+ }
+
+ if (phoneId < 0) return;
+
+ for (int i = 0; i < phoneId; i++) {
+ String str = "";
+ if ((p != null) && (i < p.length)) {
+ str = p[i];
+ }
+ propVal = propVal + str + ",";
+ }
+
+ propVal = propVal + value;
+ if (p != null) {
+ for (int i = phoneId + 1; i < p.length; i++) {
+ propVal = propVal + "," + p[i];
+ }
+ }
+
+ // TODO: workaround for QC
+ if (property.length() > SystemProperties.PROP_NAME_MAX || propVal.length() > SystemProperties.PROP_VALUE_MAX) {
+ Rlog.d(TAG, "setTelephonyProperty length too long:" + property + ", " + propVal);
+ return;
+ }
+
+ Rlog.d(TAG, "setTelephonyProperty property=" + property + " propVal=" + propVal);
+ SystemProperties.set(property, propVal);
+ }
+
+ /**
+ * Convenience function for retrieving a value from the secure settings
+ * value list as an integer. Note that internally setting values are
+ * always stored as strings; this function converts the string to an
+ * integer for you.
+ * <p>
+ * This version does not take a default value. If the setting has not
+ * been set, or the string value is not a number,
+ * it throws {@link SettingNotFoundException}.
+ *
+ * @param cr The ContentResolver to access.
+ * @param name The name of the setting to retrieve.
+ * @param index The index of the list
+ *
+ * @throws SettingNotFoundException Thrown if a setting by the given
+ * name can't be found or the setting value is not an integer.
+ *
+ * @return The value at the given index of settings.
+ * @hide
+ */
+ public static int getIntAtIndex(android.content.ContentResolver cr,
+ String name, int index)
+ throws android.provider.Settings.SettingNotFoundException {
+ String v = android.provider.Settings.Global.getString(cr, name);
+ if (v != null) {
+ String valArray[] = v.split(",");
+ if ((index >= 0) && (index < valArray.length) && (valArray[index] != null)) {
+ try {
+ return Integer.parseInt(valArray[index]);
+ } catch (NumberFormatException e) {
+ //Log.e(TAG, "Exception while parsing Integer: ", e);
+ }
+ }
+ }
+ throw new android.provider.Settings.SettingNotFoundException(name);
+ }
+
+ /**
+ * Convenience function for updating settings value as coma separated
+ * integer values. This will either create a new entry in the table if the
+ * given name does not exist, or modify the value of the existing row
+ * with that name. Note that internally setting values are always
+ * stored as strings, so this function converts the given value to a
+ * string before storing it.
+ *
+ * @param cr The ContentResolver to access.
+ * @param name The name of the setting to modify.
+ * @param index The index of the list
+ * @param value The new value for the setting to be added to the list.
+ * @return true if the value was set, false on database errors
+ * @hide
+ */
+ public static boolean putIntAtIndex(android.content.ContentResolver cr,
+ String name, int index, int value) {
+ String data = "";
+ String valArray[] = null;
+ String v = android.provider.Settings.Global.getString(cr, name);
+
+ if (v != null) {
+ valArray = v.split(",");
+ }
+
+ // Copy the elements from valArray till index
+ for (int i = 0; i < index; i++) {
+ String str = "";
+ if ((valArray != null) && (i < valArray.length)) {
+ str = valArray[i];
+ }
+ data = data + str + ",";
+ }
+
+ data = data + value;
+
+ // Copy the remaining elements from valArray if any.
+ if (valArray != null) {
+ for (int i = index+1; i < valArray.length; i++) {
+ data = data + "," + valArray[i];
+ }
+ }
+ return android.provider.Settings.Global.putString(cr, name, data);
+ }
+
+ /**
+ * Gets the telephony property.
+ *
+ * @hide
+ */
+ public static String getTelephonyProperty(String property, long subId, String defaultVal) {
+ String propVal = null;
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ String prop = SystemProperties.get(property);
+ if ((prop != null) && (prop.length() > 0)) {
+ String values[] = prop.split(",");
+ if ((phoneId >= 0) && (phoneId < values.length) && (values[phoneId] != null)) {
+ propVal = values[phoneId];
+ }
+ }
+ return propVal == null ? defaultVal : propVal;
+ }
+
+ /** @hide */
+ public int getSimCount() {
+ if(isMultiSimEnabled()) {
+ //TODO Need to get it from Telephony Devcontroller
+ return 2;
+ } else {
+ return 1;
+ }
+ }
+
+ /**
+ * Returns the IMS Service Table (IST) that was loaded from the ISIM.
+ * @return IMS Service Table or null if not present or not loaded
+ * @hide
+ */
+ public String getIsimIst() {
+ try {
+ return getSubscriberInfo().getIsimIst();
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return null;
+ }
+ }
+
+ /**
+ * Returns the IMS Proxy Call Session Control Function(PCSCF) that were loaded from the ISIM.
+ * @return an array of PCSCF strings with one PCSCF per string, or null if
+ * not present or not loaded
+ * @hide
+ */
+ public String[] getIsimPcscf() {
+ try {
+ return getSubscriberInfo().getIsimPcscf();
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return null;
+ }
+ }
+
+ /**
+ * Returns the response of ISIM Authetification through RIL.
+ * Returns null if the Authentification hasn't been successed or isn't present iphonesubinfo.
+ * @return the response of ISIM Authetification, or null if not available
+ * @hide
+ * @deprecated
+ * @see getIccSimChallengeResponse with appType=PhoneConstants.APPTYPE_ISIM
+ */
+ public String getIsimChallengeResponse(String nonce){
+ try {
+ return getSubscriberInfo().getIsimChallengeResponse(nonce);
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return null;
+ }
+ }
+
+ /**
+ * Returns the response of SIM Authentication through RIL.
+ * Returns null if the Authentication hasn't been successful
+ * @param subId subscription ID to be queried
+ * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+ * @param data authentication challenge data
+ * @return the response of SIM Authentication, or null if not available
+ * @hide
+ */
+ public String getIccSimChallengeResponse(long subId, int appType, String data) {
+ try {
+ return getSubscriberInfo().getIccSimChallengeResponse(subId, appType, data);
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ // This could happen before phone starts
+ return null;
+ }
+ }
+
+ /**
+ * Returns the response of SIM Authentication through RIL for the default subscription.
+ * Returns null if the Authentication hasn't been successful
+ * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+ * @param data authentication challenge data
+ * @return the response of SIM Authentication, or null if not available
+ * @hide
+ */
+ public String getIccSimChallengeResponse(int appType, String data) {
+ return getIccSimChallengeResponse(getDefaultSubscription(), appType, data);
+ }
+
+ /**
+ * Get P-CSCF address from PCO after data connection is established or modified.
+ *
+ * @return array of P-CSCF address
+ * @hide
+ */
+ public String[] getPcscfAddress() {
+ try {
+ return getITelephony().getPcscfAddress();
+ } catch (RemoteException e) {
+ return new String[0];
+ }
+ }
+
+ /**
+ * Set IMS registration state
+ *
+ * @param Registration state
+ * @hide
+ */
+ public void setImsRegistrationState(boolean registered) {
+ try {
+ getITelephony().setImsRegistrationState(registered);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Get the preferred network type.
* Used for device configuration by some CDMA operators.
*
@@ -1961,11 +2786,11 @@
}
/**
- * Expose the rest of ITelephony to @PrivateApi
+ * Expose the rest of ITelephony to @SystemApi
*/
/** @hide */
- @PrivateApi
+ @SystemApi
public void dial(String number) {
try {
getITelephony().dial(number);
@@ -1975,7 +2800,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public void call(String callingPackage, String number) {
try {
getITelephony().call(callingPackage, number);
@@ -1985,7 +2810,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean showCallScreen() {
try {
getTelecommService().showCallScreen(false);
@@ -1997,7 +2822,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean showCallScreenWithDialpad(boolean showDialpad) {
try {
getTelecommService().showCallScreen(showDialpad);
@@ -2009,7 +2834,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean endCall() {
try {
return getITelephony().endCall();
@@ -2020,7 +2845,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public void answerRingingCall() {
try {
getITelephony().answerRingingCall();
@@ -2030,7 +2855,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public void silenceRinger() {
try {
getTelecommService().silenceRinger();
@@ -2040,7 +2865,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean isOffhook() {
try {
return getITelephony().isOffhook();
@@ -2051,7 +2876,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean isRinging() {
try {
return getITelephony().isRinging();
@@ -2062,7 +2887,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean isIdle() {
try {
return getITelephony().isIdle();
@@ -2073,7 +2898,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean isRadioOn() {
try {
return getITelephony().isRadioOn();
@@ -2084,7 +2909,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean isSimPinEnabled() {
try {
return getITelephony().isSimPinEnabled();
@@ -2095,7 +2920,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public void cancelMissedCallsNotification() {
try {
getITelephony().cancelMissedCallsNotification();
@@ -2105,7 +2930,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean supplyPin(String pin) {
try {
return getITelephony().supplyPin(pin);
@@ -2116,7 +2941,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean supplyPuk(String puk, String pin) {
try {
return getITelephony().supplyPuk(puk, pin);
@@ -2127,7 +2952,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public int[] supplyPinReportResult(String pin) {
try {
return getITelephony().supplyPinReportResult(pin);
@@ -2138,7 +2963,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public int[] supplyPukReportResult(String puk, String pin) {
try {
return getITelephony().supplyPukReportResult(puk, pin);
@@ -2149,7 +2974,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean handlePinMmi(String dialString) {
try {
return getITelephony().handlePinMmi(dialString);
@@ -2160,7 +2985,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public void toggleRadioOnOff() {
try {
getITelephony().toggleRadioOnOff();
@@ -2170,7 +2995,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean setRadio(boolean turnOn) {
try {
return getITelephony().setRadio(turnOn);
@@ -2181,7 +3006,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean setRadioPower(boolean turnOn) {
try {
return getITelephony().setRadioPower(turnOn);
@@ -2192,7 +3017,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public void updateServiceLocation() {
try {
getITelephony().updateServiceLocation();
@@ -2202,7 +3027,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public int enableApnType(String type) {
try {
return getITelephony().enableApnType(type);
@@ -2213,7 +3038,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public int disableApnType(String type) {
try {
return getITelephony().disableApnType(type);
@@ -2224,7 +3049,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean enableDataConnectivity() {
try {
return getITelephony().enableDataConnectivity();
@@ -2235,7 +3060,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean disableDataConnectivity() {
try {
return getITelephony().disableDataConnectivity();
@@ -2246,7 +3071,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean isDataConnectivityPossible() {
try {
return getITelephony().isDataConnectivityPossible();
@@ -2257,7 +3082,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean needsOtaServiceProvisioning() {
try {
return getITelephony().needsOtaServiceProvisioning();
@@ -2268,7 +3093,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public void setDataEnabled(boolean enable) {
try {
getITelephony().setDataEnabled(enable);
@@ -2278,7 +3103,7 @@
}
/** @hide */
- @PrivateApi
+ @SystemApi
public boolean getDataEnabled() {
try {
return getITelephony().getDataEnabled();
diff --git a/telephony/java/android/telephony/VoLteServiceState.aidl b/telephony/java/android/telephony/VoLteServiceState.aidl
new file mode 100644
index 0000000..59dd04f
--- /dev/null
+++ b/telephony/java/android/telephony/VoLteServiceState.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** 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.telephony;
+
+parcelable VoLteServiceState;
+
diff --git a/telephony/java/android/telephony/VoLteServiceState.java b/telephony/java/android/telephony/VoLteServiceState.java
new file mode 100644
index 0000000..afef601b
--- /dev/null
+++ b/telephony/java/android/telephony/VoLteServiceState.java
@@ -0,0 +1,229 @@
+/*
+ * 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.telephony;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+
+/**
+ * Contains LTE network state related information.
+ *
+ * @hide
+ */
+public final class VoLteServiceState implements Parcelable {
+
+ private static final String LOG_TAG = "VoLteServiceState";
+ private static final boolean DBG = false;
+
+ //Use int max, as -1 is a valid value in signal strength
+ public static final int INVALID = 0x7FFFFFFF;
+
+ public static final int NOT_SUPPORTED = 0;
+ public static final int SUPPORTED = 1;
+
+ // Single Radio Voice Call Continuity(SRVCC) progress state
+ public static final int HANDOVER_STARTED = 0;
+ public static final int HANDOVER_COMPLETED = 1;
+ public static final int HANDOVER_FAILED = 2;
+ public static final int HANDOVER_CANCELED = 3;
+
+ private int mSrvccState;
+
+ /**
+ * Create a new VoLteServiceState from a intent notifier Bundle
+ *
+ * This method is used by PhoneStateIntentReceiver and maybe by
+ * external applications.
+ *
+ * @param m Bundle from intent notifier
+ * @return newly created VoLteServiceState
+ *
+ * @hide
+ */
+ public static VoLteServiceState newFromBundle(Bundle m) {
+ VoLteServiceState ret;
+ ret = new VoLteServiceState();
+ ret.setFromNotifierBundle(m);
+ return ret;
+ }
+
+ /**
+ * Empty constructor
+ *
+ * @hide
+ */
+ public VoLteServiceState() {
+ initialize();
+ }
+
+ /**
+ * Constructor
+ *
+ * @hide
+ */
+ public VoLteServiceState(int srvccState) {
+ initialize();
+
+ mSrvccState = srvccState;
+ }
+
+ /**
+ * Copy constructors
+ *
+ * @param s Source VoLteServiceState
+ *
+ * @hide
+ */
+ public VoLteServiceState(VoLteServiceState s) {
+ copyFrom(s);
+ }
+
+ /**
+ * Initialize values to defaults.
+ *
+ * @hide
+ */
+ private void initialize() {
+ mSrvccState = INVALID;
+ }
+
+ /**
+ * @hide
+ */
+ protected void copyFrom(VoLteServiceState s) {
+ mSrvccState = s.mSrvccState;
+ }
+
+ /**
+ * Construct a VoLteServiceState object from the given parcel.
+ *
+ * @hide
+ */
+ public VoLteServiceState(Parcel in) {
+ if (DBG) log("Size of VoLteServiceState parcel:" + in.dataSize());
+
+ mSrvccState = in.readInt();
+ }
+
+ /**
+ * {@link Parcelable#writeToParcel}
+ */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mSrvccState);
+ }
+
+ /**
+ * {@link Parcelable#describeContents}
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * {@link Parcelable.Creator}
+ *
+ * @hide
+ */
+ public static final Parcelable.Creator<VoLteServiceState> CREATOR = new Parcelable.Creator() {
+ public VoLteServiceState createFromParcel(Parcel in) {
+ return new VoLteServiceState(in);
+ }
+
+ public VoLteServiceState[] newArray(int size) {
+ return new VoLteServiceState[size];
+ }
+ };
+
+ /**
+ * Validate the individual fields as per the range
+ * specified in ril.h
+ * Set to invalid any field that is not in the valid range
+ *
+ * @return
+ * Valid values for all fields
+ * @hide
+ */
+ public void validateInput() {
+ }
+
+ public int hashCode() {
+ int primeNum = 31;
+ return ((mSrvccState * primeNum));
+ }
+
+ /**
+ * @return true if the LTE network states are the same
+ */
+ @Override
+ public boolean equals (Object o) {
+ VoLteServiceState s;
+
+ try {
+ s = (VoLteServiceState) o;
+ } catch (ClassCastException ex) {
+ return false;
+ }
+
+ if (o == null) {
+ return false;
+ }
+
+ return (mSrvccState == s.mSrvccState);
+ }
+
+ /**
+ * @return string representation.
+ */
+ @Override
+ public String toString() {
+ return ("VoLteServiceState:"
+ + " " + mSrvccState);
+ }
+
+ /**
+ * Set VoLteServiceState based on intent notifier map
+ *
+ * @param m intent notifier map
+ * @hide
+ */
+ private void setFromNotifierBundle(Bundle m) {
+ mSrvccState = m.getInt("mSrvccState");
+ }
+
+ /**
+ * Set intent notifier Bundle based on VoLteServiceState
+ *
+ * @param m intent notifier Bundle
+ * @hide
+ */
+ public void fillInNotifierBundle(Bundle m) {
+ m.putInt("mSrvccState", mSrvccState);
+ }
+
+ public int getSrvccState() {
+ return mSrvccState;
+ }
+
+ /**
+ * log
+ */
+ private static void log(String s) {
+ Rlog.w(LOG_TAG, s);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index f8dd7cf..745c9d0 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -37,6 +37,9 @@
import com.android.i18n.phonenumbers.NumberParseException;
import com.android.i18n.phonenumbers.PhoneNumberUtil;
import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
+import android.telephony.SubscriptionManager;
+
+import android.telephony.TelephonyManager;
import java.util.Locale;
@@ -233,6 +236,7 @@
info.contactExists = true;
}
cursor.close();
+ cursor = null;
}
info.needUpdate = false;
@@ -269,6 +273,23 @@
public static CallerInfo getCallerInfo(Context context, String number) {
if (VDBG) Rlog.v(TAG, "getCallerInfo() based on number...");
+ long subId = SubscriptionManager.getDefaultSubId();
+ return getCallerInfo(context, number, subId);
+ }
+
+ /**
+ * getCallerInfo given a phone number and subscription, look up in the call-log database
+ * for the matching caller id info.
+ * @param context the context used to get the ContentResolver
+ * @param number the phone number used to lookup caller id
+ * @param subId the subscription for checking for if voice mail number or not
+ * @return the CallerInfo which contains the caller id for the given
+ * number. The returned CallerInfo is null if no number is supplied. If
+ * a matching number is not found, then a generic caller info is returned,
+ * with all relevant fields empty or null.
+ */
+ public static CallerInfo getCallerInfo(Context context, String number, long subId) {
+
if (TextUtils.isEmpty(number)) {
return null;
}
@@ -278,7 +299,7 @@
// shortcut and skip the query.
if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) {
return new CallerInfo().markAsEmergency(context);
- } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+ } else if (PhoneNumberUtils.isVoiceMailNumber(subId, number)) {
return new CallerInfo().markAsVoiceMail();
}
@@ -400,10 +421,17 @@
// TODO: As in the emergency number handling, we end up writing a
// string in the phone number field.
/* package */ CallerInfo markAsVoiceMail() {
+
+ long subId = SubscriptionManager.getDefaultSubId();
+ return markAsVoiceMail(subId);
+
+ }
+
+ /* package */ CallerInfo markAsVoiceMail(long subId) {
mIsVoiceMail = true;
try {
- String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag();
+ String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag(subId);
phoneNumber = voiceMailLabel;
} catch (SecurityException se) {
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 34fed5e..fe403d9 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -24,12 +24,15 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemProperties;
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.PhoneLookup;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.telephony.Rlog;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
/**
* Helper class to make it easier to run asynchronous caller-id lookup queries.
@@ -75,6 +78,8 @@
public Object cookie;
public int event;
public String number;
+
+ public long subId;
}
@@ -207,11 +212,17 @@
// However, if there is any code that calls this method, we should
// check the parameters to make sure they're viable.
if (DBG) Rlog.d(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request.");
+ if (cursor != null) {
+ cursor.close();
+ }
return;
}
if (cw.event == EVENT_END_OF_QUEUE) {
release();
+ if (cursor != null) {
+ cursor.close();
+ }
return;
}
@@ -232,7 +243,7 @@
// comments at the top of CallerInfo class).
mCallerInfo = new CallerInfo().markAsEmergency(mQueryContext);
} else if (cw.event == EVENT_VOICEMAIL_NUMBER) {
- mCallerInfo = new CallerInfo().markAsVoiceMail();
+ mCallerInfo = new CallerInfo().markAsVoiceMail(cw.subId);
} else {
mCallerInfo = CallerInfo.getCallerInfo(mQueryContext, mQueryUri, cursor);
if (DBG) Rlog.d(LOG_TAG, "==> Got mCallerInfo: " + mCallerInfo);
@@ -289,6 +300,10 @@
" for token: " + token + mCallerInfo);
cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
}
+
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
@@ -334,6 +349,25 @@
*/
public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
OnQueryCompleteListener listener, Object cookie) {
+
+ long subId = SubscriptionManager.getDefaultSubId();
+ return startQuery(token, context, number, listener, cookie, subId);
+ }
+
+ /**
+ * Factory method to start the query based on a number with specific subscription.
+ *
+ * Note: if the number contains an "@" character we treat it
+ * as a SIP address, and look it up directly in the Data table
+ * rather than using the PhoneLookup table.
+ * TODO: But eventually we should expose two separate methods, one for
+ * numbers and one for SIP addresses, and then have
+ * PhoneUtils.startGetCallerInfo() decide which one to call based on
+ * the phone type of the incoming connection.
+ */
+ public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
+ OnQueryCompleteListener listener, Object cookie, long subId) {
+
if (DBG) {
Rlog.d(LOG_TAG, "##### CallerInfoAsyncQuery startQuery()... #####");
Rlog.d(LOG_TAG, "- number: " + /*number*/ "xxxxxxx");
@@ -397,11 +431,12 @@
cw.listener = listener;
cw.cookie = cookie;
cw.number = number;
+ cw.subId = subId;
// check to see if these are recognized numbers, and use shortcuts if we can.
if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) {
cw.event = EVENT_EMERGENCY_NUMBER;
- } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+ } else if (PhoneNumberUtils.isVoiceMailNumber(subId, number)) {
cw.event = EVENT_VOICEMAIL_NUMBER;
} else {
cw.event = EVENT_NEW_QUERY;
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 3f36645..a95336e 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -23,6 +23,7 @@
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
+import android.telephony.VoLteServiceState;
oneway interface IPhoneStateListener {
void onServiceStateChanged(in ServiceState serviceState);
@@ -41,5 +42,6 @@
void onPreciseCallStateChanged(in PreciseCallState callState);
void onPreciseDataConnectionStateChanged(in PreciseDataConnectionState dataConnectionState);
void onDataConnectionRealTimeInfoChanged(in DataConnectionRealTimeInfo dcRtInfo);
+ void onVoLteServiceStateChanged(in VoLteServiceState lteState);
}
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index 03940dc..4734965 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -28,6 +28,13 @@
String getDeviceId();
/**
+ * Retrieves the unique device ID of a subId for the device, e.g., IMEI
+ * for GSM phones.
+ */
+ String getDeviceIdUsingSubId(long subId);
+
+
+ /**
* Retrieves the software version number for the device, e.g., IMEI/SV
* for GSM phones.
*/
@@ -39,46 +46,94 @@
String getSubscriberId();
/**
+ * Retrieves the unique subscriber ID of a given subId, e.g., IMSI for GSM phones.
+ */
+ String getSubscriberIdUsingSubId(long subId);
+
+ /**
* Retrieves the Group Identifier Level1 for GSM phones.
*/
String getGroupIdLevel1();
/**
+ * Retrieves the Group Identifier Level1 for GSM phones of a subId.
+ */
+ String getGroupIdLevel1UsingSubId(long subId);
+
+ /**
* Retrieves the serial number of the ICC, if applicable.
*/
String getIccSerialNumber();
/**
+ * Retrieves the serial number of a given subId.
+ */
+ String getIccSerialNumberUsingSubId(long subId);
+
+ /**
* Retrieves the phone number string for line 1.
*/
String getLine1Number();
/**
+ * Retrieves the phone number string for line 1 of a subcription.
+ */
+ String getLine1NumberUsingSubId(long subId);
+
+
+ /**
* Retrieves the alpha identifier for line 1.
*/
String getLine1AlphaTag();
/**
+ * Retrieves the alpha identifier for line 1 of a subId.
+ */
+ String getLine1AlphaTagUsingSubId(long subId);
+
+
+ /**
* Retrieves MSISDN Number.
*/
String getMsisdn();
/**
+ * Retrieves the Msisdn of a subId.
+ */
+ String getMsisdnUsingSubId(long subId);
+
+ /**
* Retrieves the voice mail number.
*/
String getVoiceMailNumber();
/**
+ * Retrieves the voice mail number of a given subId.
+ */
+ String getVoiceMailNumberUsingSubId(long subId);
+
+ /**
* Retrieves the complete voice mail number.
*/
String getCompleteVoiceMailNumber();
/**
+ * Retrieves the complete voice mail number for particular subId
+ */
+ String getCompleteVoiceMailNumberUsingSubId(long subId);
+
+ /**
* Retrieves the alpha identifier associated with the voice mail number.
*/
String getVoiceMailAlphaTag();
/**
+ * Retrieves the alpha identifier associated with the voice mail number
+ * of a subId.
+ */
+ String getVoiceMailAlphaTagUsingSubId(long subId);
+
+ /**
* Returns the IMS private user identity (IMPI) that was loaded from the ISIM.
* @return the IMPI, or null if not present or not loaded
*/
@@ -96,4 +151,38 @@
* not present or not loaded
*/
String[] getIsimImpu();
+
+ /**
+ * Returns the IMS Service Table (IST) that was loaded from the ISIM.
+ * @return IMS Service Table or null if not present or not loaded
+ */
+ String getIsimIst();
+
+ /**
+ * Returns the IMS Proxy Call Session Control Function(PCSCF) that were loaded from the ISIM.
+ * @return an array of PCSCF strings with one PCSCF per string, or null if
+ * not present or not loaded
+ */
+ String[] getIsimPcscf();
+
+ /**
+ * TODO: Deprecate and remove this interface. Superceded by getIccsimChallengeResponse.
+ * Returns the response of ISIM Authetification through RIL.
+ * @return the response of ISIM Authetification, or null if
+ * the Authentification hasn't been successed or isn't present iphonesubinfo.
+ */
+ String getIsimChallengeResponse(String nonce);
+
+ /**
+ * Returns the response of the SIM application on the UICC to authentication
+ * challenge/response algorithm. The data string and challenge response are
+ * Base64 encoded Strings.
+ * Can support EAP-SIM, EAP-AKA with results encoded per 3GPP TS 31.102.
+ *
+ * @param subId subscription ID to be queried
+ * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+ * @param data authentication challenge data
+ * @return challenge response
+ */
+ String getIccSimChallengeResponse(long subId, int appType, String data);
}
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 3e8db06..9e975e9 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -42,6 +42,13 @@
List<SmsRawData> getAllMessagesFromIccEf(String callingPkg);
/**
+ * Retrieves all messages currently stored on ICC.
+ * @param subId the subId id.
+ * @return list of SmsRawData of all sms on ICC
+ */
+ List<SmsRawData> getAllMessagesFromIccEfUsingSubId(in long subId, String callingPkg);
+
+ /**
* Update the specified message on the ICC.
*
* @param messageIndex record index of message to update
@@ -56,6 +63,21 @@
in byte[] pdu);
/**
+ * Update the specified message on the ICC.
+ *
+ * @param messageIndex record index of message to update
+ * @param newStatus new message status (STATUS_ON_ICC_READ,
+ * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
+ * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
+ * @param pdu the raw PDU to store
+ * @param subId the subId id.
+ * @return success or not
+ *
+ */
+ boolean updateMessageOnIccEfUsingSubId(in long subId, String callingPkg,
+ int messageIndex, int newStatus, in byte[] pdu);
+
+ /**
* Copy a raw SMS PDU to the ICC.
*
* @param pdu the raw PDU to store
@@ -67,6 +89,19 @@
boolean copyMessageToIccEf(String callingPkg, int status, in byte[] pdu, in byte[] smsc);
/**
+ * Copy a raw SMS PDU to the ICC.
+ *
+ * @param pdu the raw PDU to store
+ * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
+ * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
+ * @param subId the subId id.
+ * @return success or not
+ *
+ */
+ boolean copyMessageToIccEfUsingSubId(in long subId, String callingPkg, int status,
+ in byte[] pdu, in byte[] smsc);
+
+ /**
* Send a data SMS.
*
* @param smsc the SMSC to send the message through, or NULL for the
@@ -93,6 +128,34 @@
in byte[] data, in PendingIntent sentIntent, in PendingIntent deliveryIntent);
/**
+ * Send a data SMS.
+ *
+ * @param smsc the SMSC to send the message through, or NULL for the
+ * default SMSC
+ * @param data the body of the message to send
+ * @param sentIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is sucessfully sent, or failed.
+ * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applicaitons,
+ * which cause smaller number of SMS to be sent in checking period.
+ * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is delivered to the recipient. The
+ * raw pdu of the status report is in the extended data ("pdu").
+ * @param subId the subId id.
+ */
+ void sendDataUsingSubId(long subId, String callingPkg, in String destAddr,
+ in String scAddr, in int destPort, in byte[] data, in PendingIntent sentIntent,
+ in PendingIntent deliveryIntent);
+
+ /**
* Send an SMS.
*
* @param smsc the SMSC to send the message through, or NULL for the
@@ -119,6 +182,47 @@
in PendingIntent sentIntent, in PendingIntent deliveryIntent);
/**
+ * Send an SMS.
+ *
+ * @param smsc the SMSC to send the message through, or NULL for the
+ * default SMSC
+ * @param text the body of the message to send
+ * @param sentIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is sucessfully sent, or failed.
+ * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applications,
+ * which cause smaller number of SMS to be sent in checking period.
+ * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is delivered to the recipient. The
+ * raw pdu of the status report is in the extended data ("pdu").
+ * @param subId the subId on which the SMS has to be sent.
+ */
+ void sendTextUsingSubId(in long subId, String callingPkg, in String destAddr,
+ in String scAddr, in String text, in PendingIntent sentIntent,
+ in PendingIntent deliveryIntent);
+
+ /**
+ * Inject an SMS PDU into the android platform.
+ *
+ * @param pdu is the byte array of pdu to be injected into android application framework
+ * @param format is the format of SMS pdu (android.telephony.SmsMessage.FORMAT_3GPP or
+ * android.telephony.SmsMessage.FORMAT_3GPP2)
+ * @param receivedIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is successfully received by the
+ * android application framework. This intent is broadcasted at
+ * the same time an SMS received from radio is acknowledged back.
+ */
+ void injectSmsPdu(in byte[] pdu, String format, in PendingIntent receivedIntent);
+
+ /**
* Send a multi-part text based SMS.
*
* @param destinationAddress the address to send the message to
@@ -145,6 +249,34 @@
in List<PendingIntent> deliveryIntents);
/**
+ * Send a multi-part text based SMS.
+ *
+ * @param destinationAddress the address to send the message to
+ * @param scAddress is the service center address or null to use
+ * the current default SMSC
+ * @param parts an <code>ArrayList</code> of strings that, in order,
+ * comprise the original message
+ * @param sentIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * or one of these errors:
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code>
+ * <code>RESULT_ERROR_RADIO_OFF</code>
+ * <code>RESULT_ERROR_NULL_PDU</code>.
+ * @param deliveryIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been delivered
+ * to the recipient. The raw pdu of the status report is in the
+ * extended data ("pdu").
+ * @param subId the subId on which the SMS has to be sent.
+ */
+ void sendMultipartTextUsingSubId(in long subId, String callingPkg,
+ in String destinationAddress, in String scAddress,
+ in List<String> parts, in List<PendingIntent> sentIntents,
+ in List<PendingIntent> deliveryIntents);
+
+ /**
* Enable reception of cell broadcast (SMS-CB) messages with the given
* message identifier. Note that if two different clients enable the same
* message identifier, they must both disable it for the device to stop
@@ -159,6 +291,21 @@
boolean enableCellBroadcast(int messageIdentifier);
/**
+ * Enable reception of cell broadcast (SMS-CB) messages with the given
+ * message identifier. Note that if two different clients enable the same
+ * message identifier, they must both disable it for the device to stop
+ * receiving those messages.
+ *
+ * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) or
+ * C.R1001-G (3GPP2)
+ * @param subId for which the broadcast has to be enabled
+ * @return true if successful, false otherwise
+ *
+ * @see #disableCellBroadcast(int)
+ */
+ boolean enableCellBroadcastUsingSubId(in long subId, int messageIdentifier);
+
+ /**
* Disable reception of cell broadcast (SMS-CB) messages with the given
* message identifier. Note that if two different clients enable the same
* message identifier, they must both disable it for the device to stop
@@ -172,6 +319,21 @@
*/
boolean disableCellBroadcast(int messageIdentifier);
+ /**
+ * Disable reception of cell broadcast (SMS-CB) messages with the given
+ * message identifier. Note that if two different clients enable the same
+ * message identifier, they must both disable it for the device to stop
+ * receiving those messages.
+ *
+ * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) or
+ * C.R1001-G (3GPP2)
+ * @param subId for which the broadcast has to be disabled
+ * @return true if successful, false otherwise
+ *
+ * @see #enableCellBroadcast(int)
+ */
+ boolean disableCellBroadcastUsingSubId(in long subId, int messageIdentifier);
+
/*
* Enable reception of cell broadcast (SMS-CB) messages with the given
* message identifier range. Note that if two different clients enable
@@ -188,6 +350,23 @@
*/
boolean enableCellBroadcastRange(int startMessageId, int endMessageId);
+ /*
+ * Enable reception of cell broadcast (SMS-CB) messages with the given
+ * message identifier range. Note that if two different clients enable
+ * a message identifier range, they must both disable it for the device
+ * to stop receiving those messages.
+ *
+ * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) or
+ * C.R1001-G (3GPP2)
+ * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) or
+ * C.R1001-G (3GPP2)
+ * @param subId for which the broadcast has to be enabled
+ * @return true if successful, false otherwise
+ *
+ * @see #disableCellBroadcastRange(int, int)
+ */
+ boolean enableCellBroadcastRangeUsingSubId(long subId, int startMessageId, int endMessageId);
+
/**
* Disable reception of cell broadcast (SMS-CB) messages with the given
* message identifier range. Note that if two different clients enable
@@ -205,18 +384,52 @@
boolean disableCellBroadcastRange(int startMessageId, int endMessageId);
/**
+ * Disable reception of cell broadcast (SMS-CB) messages with the given
+ * message identifier range. Note that if two different clients enable
+ * a message identifier range, they must both disable it for the device
+ * to stop receiving those messages.
+ *
+ * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) or
+ * C.R1001-G (3GPP2)
+ * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) or
+ * C.R1001-G (3GPP2)
+ * @param subId for which the broadcast has to be disabled
+ * @return true if successful, false otherwise
+ *
+ * @see #enableCellBroadcastRange(int, int, int)
+ */
+ boolean disableCellBroadcastRangeUsingSubId(long subId, int startMessageId,
+ int endMessageId);
+
+ /**
* Returns the premium SMS send permission for the specified package.
* Requires system permission.
*/
int getPremiumSmsPermission(String packageName);
/**
+ * Returns the premium SMS send permission for the specified package.
+ * Requires system permission.
+ */
+ int getPremiumSmsPermissionUsingSubId(long subId, String packageName);
+
+ /**
* Set the SMS send permission for the specified package.
* Requires system permission.
*/
void setPremiumSmsPermission(String packageName, int permission);
/**
+ * Set the SMS send permission for the specified package.
+ * Requires system permission.
+ */
+ /**
+ * Set the SMS send permission for the specified package.
+ * Requires system permission.
+ */
+ void setPremiumSmsPermissionUsingSubId(long subId, String packageName, int permission);
+
+ /**
* SMS over IMS is supported if IMS is registered and SMS is supported
* on IMS.
*
@@ -227,6 +440,23 @@
boolean isImsSmsSupported();
/**
+ * SMS over IMS is supported if IMS is registered and SMS is supported
+ * on IMS.
+ * @param subId for subId which isImsSmsSupported is queried
+ * @return true if SMS over IMS is supported, false otherwise
+ *
+ * @see #getImsSmsFormat()
+ */
+ boolean isImsSmsSupportedUsingSubId(long subId);
+
+ /*
+ * get user prefered SMS subId
+ * @return subId id
+ */
+ long getPreferredSmsSubscription();
+
+
+ /**
* Gets SMS format supported on IMS. SMS over IMS format is
* either 3GPP or 3GPP2.
*
@@ -237,4 +467,25 @@
* @see #isImsSmsSupported()
*/
String getImsSmsFormat();
+
+ /**
+ * Gets SMS format supported on IMS. SMS over IMS format is
+ * either 3GPP or 3GPP2.
+ * @param subId for subId which getImsSmsFormat is queried
+ * @return android.telephony.SmsMessage.FORMAT_3GPP,
+ * android.telephony.SmsMessage.FORMAT_3GPP2
+ * or android.telephony.SmsMessage.FORMAT_UNKNOWN
+ *
+ * @see #isImsSmsSupported()
+ */
+ String getImsSmsFormatUsingSubId(long subId);
+
+
+
+
+ /*
+ * Get SMS prompt property, enabled or not
+ * @return true if enabled, false otherwise
+ */
+ boolean isSMSPromptEnabled();
}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
new file mode 100755
index 0000000..6021ccf
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -0,0 +1,153 @@
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.android.internal.telephony;
+
+import android.app.PendingIntent;
+import android.telephony.SubInfoRecord;
+
+interface ISub {
+ /**
+ * Get the SubInfoRecord according to an index
+ * @param context Context provided by caller
+ * @param subId The unique SubInfoRecord index in database
+ * @return SubInfoRecord, maybe null
+ */
+ SubInfoRecord getSubInfoUsingSubId(long subId);
+
+ /**
+ * Get the SubInfoRecord according to an IccId
+ * @param context Context provided by caller
+ * @param iccId the IccId of SIM card
+ * @return SubInfoRecord, maybe null
+ */
+ List<SubInfoRecord> getSubInfoUsingIccId(String iccId);
+
+ /**
+ * Get the SubInfoRecord according to slotId
+ * @param context Context provided by caller
+ * @param slotId the slot which the SIM is inserted
+ * @return SubInfoRecord, maybe null
+ */
+ List<SubInfoRecord> getSubInfoUsingSlotId(int slotId);
+
+ /**
+ * Get all the SubInfoRecord(s) in subinfo database
+ * @param context Context provided by caller
+ * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before
+ */
+ List<SubInfoRecord> getAllSubInfoList();
+
+ /**
+ * Get the SubInfoRecord(s) of the currently inserted SIM(s)
+ * @param context Context provided by caller
+ * @return Array list of currently inserted SubInfoRecord(s)
+ */
+ List<SubInfoRecord> getActivatedSubInfoList();
+
+ /**
+ * Get the SUB count of all SUB(s) in subinfo database
+ * @param context Context provided by caller
+ * @return all SIM count in database, include what was inserted before
+ */
+ int getAllSubInfoCount();
+
+ /**
+ * Add a new SubInfoRecord to subinfo database if needed
+ * @param context Context provided by caller
+ * @param iccId the IccId of the SIM card
+ * @param slotId the slot which the SIM is inserted
+ * @return the URL of the newly created row or the updated row
+ */
+ int addSubInfoRecord(String iccId, int slotId);
+
+ /**
+ * Set SIM color by simInfo index
+ * @param context Context provided by caller
+ * @param color the color of the SIM
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ int setColor(int color, long subId);
+
+ /**
+ * Set display name by simInfo index
+ * @param context Context provided by caller
+ * @param displayName the display name of SIM card
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ int setDisplayName(String displayName, long subId);
+
+ /**
+ * Set display name by simInfo index with name source
+ * @param context Context provided by caller
+ * @param displayName the display name of SIM card
+ * @param subId the unique SubInfoRecord index in database
+ * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT
+ * @return the number of records updated
+ */
+ int setDisplayNameUsingSrc(String displayName, long subId, long nameSource);
+
+ /**
+ * Set phone number by subId
+ * @param context Context provided by caller
+ * @param number the phone number of the SIM
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ int setDispalyNumber(String number, long subId);
+
+ /**
+ * Set number display format. 0: none, 1: the first four digits, 2: the last four digits
+ * @param context Context provided by caller
+ * @param format the display format of phone number
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ int setDisplayNumberFormat(int format, long subId);
+
+ /**
+ * Set data roaming by simInfo index
+ * @param context Context provided by caller
+ * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ int setDataRoaming(int roaming, long subId);
+
+ int getSlotId(long subId);
+
+ long[] getSubId(int slotId);
+
+ long getDefaultSubId();
+
+ int clearSubInfo();
+
+ int getPhoneId(long subId);
+
+ /**
+ * Get the default data subscription
+ * @return Id of the data subscription
+ */
+ long getDefaultDataSubId();
+
+ void setDefaultDataSubId(long subId);
+
+ long getDefaultVoiceSubId();
+
+ void setDefaultVoiceSubId(long subId);
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index acaa8de..407da87 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -16,14 +16,11 @@
package com.android.internal.telephony;
-import android.content.ComponentName;
import android.os.Bundle;
-import android.telephony.CellInfo;
+import java.util.List;
import android.telephony.NeighboringCellInfo;
+import android.telephony.CellInfo;
-import java.util.List;
-
-import java.util.List;
/**
* Interface used to interact with the phone. Mostly this is used by the
@@ -56,6 +53,13 @@
boolean endCall();
/**
+ * End call on particular subId or go to the Home screen
+ * @param subId user preferred subId.
+ * @return whether it hung up
+ */
+ boolean endCallUsingSubId(long subId);
+
+ /**
* Answer the currently-ringing call.
*
* If there's already a current active call, that call will be
@@ -92,6 +96,23 @@
boolean isOffhook();
/**
+ * Check if a particular subId has an active or holding call
+ *
+ * @param subId user preferred subId.
+ * @return true if the phone state is OFFHOOK.
+ */
+ boolean isOffhookUsingSubId(long subId);
+
+ /**
+ * Check if an incoming phone call is ringing or call waiting
+ * on a particular subId.
+ *
+ * @param subId user preferred subId.
+ * @return true if the phone state is RINGING.
+ */
+ boolean isRingingUsingSubId(long subId);
+
+ /**
* Check if an incoming phone call is ringing or call waiting.
* @return true if the phone state is RINGING.
*/
@@ -104,12 +125,27 @@
boolean isIdle();
/**
+ * Check if the phone is idle on a particular subId.
+ *
+ * @param subId user preferred subId.
+ * @return true if the phone state is IDLE.
+ */
+ boolean isIdleUsingSubId(long subId);
+
+ /**
* Check to see if the radio is on or not.
* @return returns true if the radio is on.
*/
boolean isRadioOn();
/**
+ * Check to see if the radio is on or not on particular subId.
+ * @param subId user preferred subId.
+ * @return returns true if the radio is on.
+ */
+ boolean isRadioOnUsingSubId(long subId);
+
+ /**
* Check if the SIM pin lock is enabled.
* @return true if the SIM pin lock is enabled.
*/
@@ -128,6 +164,15 @@
boolean supplyPin(String pin);
/**
+ * Supply a pin to unlock the SIM for particular subId.
+ * Blocks until a result is determined.
+ * @param pin The pin to check.
+ * @param subId user preferred subId.
+ * @return whether the operation was a success.
+ */
+ boolean supplyPinUsingSubId(long subId, String pin);
+
+ /**
* Supply puk to unlock the SIM and set SIM pin to new pin.
* Blocks until a result is determined.
* @param puk The puk to check.
@@ -137,6 +182,16 @@
boolean supplyPuk(String puk, String pin);
/**
+ * Supply puk to unlock the SIM and set SIM pin to new pin.
+ * Blocks until a result is determined.
+ * @param puk The puk to check.
+ * pin The new pin to be set in SIM
+ * @param subId user preferred subId.
+ * @return whether the operation was a success.
+ */
+ boolean supplyPukUsingSubId(long subId, String puk, String pin);
+
+ /**
* Supply a pin to unlock the SIM. Blocks until a result is determined.
* Returns a specific success/error code.
* @param pin The pin to check.
@@ -146,6 +201,15 @@
int[] supplyPinReportResult(String pin);
/**
+ * Supply a pin to unlock the SIM. Blocks until a result is determined.
+ * Returns a specific success/error code.
+ * @param pin The pin to check.
+ * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
+ * retValue[1] = number of attempts remaining if known otherwise -1
+ */
+ int[] supplyPinReportResultUsingSubId(long subId, String pin);
+
+ /**
* Supply puk to unlock the SIM and set SIM pin to new pin.
* Blocks until a result is determined.
* Returns a specific success/error code
@@ -157,6 +221,17 @@
int[] supplyPukReportResult(String puk, String pin);
/**
+ * Supply puk to unlock the SIM and set SIM pin to new pin.
+ * Blocks until a result is determined.
+ * Returns a specific success/error code
+ * @param puk The puk to check
+ * pin The pin to check.
+ * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
+ * retValue[1] = number of attempts remaining if known otherwise -1
+ */
+ int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin);
+
+ /**
* Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
* without SEND (so <code>dial</code> is not appropriate).
*
@@ -166,16 +241,38 @@
boolean handlePinMmi(String dialString);
/**
+ * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
+ * without SEND (so <code>dial</code> is not appropriate) for
+ * a particular subId.
+ * @param dialString the MMI command to be executed.
+ * @param subId user preferred subId.
+ * @return true if MMI command is executed.
+ */
+ boolean handlePinMmiUsingSubId(long subId, String dialString);
+
+ /**
* Toggles the radio on or off.
*/
void toggleRadioOnOff();
/**
+ * Toggles the radio on or off on particular subId.
+ * @param subId user preferred subId.
+ */
+ void toggleRadioOnOffUsingSubId(long subId);
+
+ /**
* Set the radio to on or off
*/
boolean setRadio(boolean turnOn);
/**
+ * Set the radio to on or off on particular subId.
+ * @param subId user preferred subId.
+ */
+ boolean setRadioUsingSubId(long subId, boolean turnOn);
+
+ /**
* Set the radio to on or off unconditionally
*/
boolean setRadioPower(boolean turnOn);
@@ -186,16 +283,35 @@
void updateServiceLocation();
/**
+ * Request to update location information for a subscrition in service state
+ * @param subId user preferred subId.
+ */
+ void updateServiceLocationUsingSubId(long subId);
+
+ /**
* Enable location update notifications.
*/
void enableLocationUpdates();
/**
+ * Enable location update notifications.
+ * @param subId user preferred subId.
+ */
+ void enableLocationUpdatesUsingSubId(long subId);
+
+ /**
* Disable location update notifications.
*/
void disableLocationUpdates();
/**
+ * Disable location update notifications.
+ * @param subId user preferred subId.
+ */
+ void disableLocationUpdatesUsingSubId(long subId);
+
+
+ /**
* Enable a specific APN type.
*/
int enableApnType(String type);
@@ -206,6 +322,16 @@
int disableApnType(String type);
/**
+ * Enable a specific APN type with subscription.
+ */
+ int enableApnTypeUsingSub(long subId, String type);
+
+ /**
+ * Disable a specific APN type with subscription.
+ */
+ int disableApnTypeUsingSub(long subId, String type);
+
+ /**
* Allow mobile data connections.
*/
boolean enableDataConnectivity();
@@ -228,6 +354,12 @@
List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg);
int getCallState();
+
+ /**
+ * Returns the call state for a subId.
+ */
+ int getCallStateUsingSubId(long subId);
+
int getDataActivity();
int getDataState();
@@ -239,11 +371,25 @@
int getActivePhoneType();
/**
+ * Returns the current active phone type as integer for particular subId.
+ * Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE
+ * and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE
+ * @param subId user preferred subId.
+ */
+ int getActivePhoneTypeUsingSubId(long subId);
+
+ /**
* Returns the CDMA ERI icon index to display
*/
int getCdmaEriIconIndex();
/**
+ * Returns the CDMA ERI icon index to display on particular subId.
+ * @param subId user preferred subId.
+ */
+ int getCdmaEriIconIndexUsingSubId(long subId);
+
+ /**
* Returns the CDMA ERI icon mode,
* 0 - ON
* 1 - FLASHING
@@ -251,11 +397,25 @@
int getCdmaEriIconMode();
/**
+ * Returns the CDMA ERI icon mode on particular subId,
+ * 0 - ON
+ * 1 - FLASHING
+ * @param subId user preferred subId.
+ */
+ int getCdmaEriIconModeUsingSubId(long subId);
+
+ /**
* Returns the CDMA ERI text,
*/
String getCdmaEriText();
/**
+ * Returns the CDMA ERI text for particular subId,
+ * @param subId user preferred subId.
+ */
+ String getCdmaEriTextUsingSubId(long subId);
+
+ /**
* Returns true if OTA service provisioning needs to run.
* Only relevant on some technologies, others will always
* return false.
@@ -268,26 +428,61 @@
int getVoiceMessageCount();
/**
+ * Returns the unread count of voicemails for a subId.
+ * @param subId user preferred subId.
+ * Returns the unread count of voicemails
+ */
+ int getVoiceMessageCountUsingSubId(long subId);
+
+ /**
* Returns the network type for data transmission
*/
int getNetworkType();
/**
+ * Returns the network type of a subId.
+ * @param subId user preferred subId.
+ * Returns the network type
+ */
+ int getNetworkTypeUsingSubId(long subId);
+
+ /**
* Returns the network type for data transmission
*/
int getDataNetworkType();
/**
+ * Returns the data network type of a subId
+ * @param subId user preferred subId.
+ * Returns the network type
+ */
+ int getDataNetworkTypeUsingSubId(long subId);
+
+ /**
* Returns the network type for voice
*/
int getVoiceNetworkType();
/**
+ * Returns the voice network type of a subId
+ * @param subId user preferred subId.
+ * Returns the network type
+ */
+ int getVoiceNetworkTypeUsingSubId(long subId);
+
+ /**
* Return true if an ICC card is present
*/
boolean hasIccCard();
/**
+ * Return true if an ICC card is present for a subId.
+ * @param slotId user preferred slotId.
+ * Return true if an ICC card is present
+ */
+ boolean hasIccCardUsingSlotId(long slotId);
+
+ /**
* Return if the current radio is LTE on CDMA. This
* is a tri-state return value as for a period of time
* the mode may be unknown.
@@ -298,6 +493,16 @@
int getLteOnCdmaMode();
/**
+ * Return if the current radio is LTE on CDMA. This
+ * is a tri-state return value as for a period of time
+ * the mode may be unknown.
+ *
+ * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
+ * or {@link PHone#LTE_ON_CDMA_TRUE}
+ */
+ int getLteOnCdmaModeUsingSubId(long subId);
+
+ /**
* Returns the all observed cell information of the device.
*/
List<CellInfo> getAllCellInfo();
@@ -308,6 +513,12 @@
void setCellInfoListRate(int rateInMillis);
/**
+ * get default sim
+ * @return sim id
+ */
+ int getDefaultSim();
+
+ /**
* Opens a logical channel to the ICC card.
*
* Input parameters equivalent to TS 27.007 AT+CCHO command.
@@ -428,4 +639,16 @@
* @return true on enabled
*/
boolean getDataEnabled();
+
+ /**
+ * Get P-CSCF address from PCO after data connection is established or modified.
+ */
+ String[] getPcscfAddress();
+
+ /**
+ * Set IMS registration state
+ */
+ void setImsRegistrationState(boolean registered);
+
}
+
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index b104c11..fd2d1c7 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -24,22 +24,36 @@
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
+import android.telephony.CellInfo;
+import android.telephony.VoLteServiceState;
import com.android.internal.telephony.IPhoneStateListener;
interface ITelephonyRegistry {
void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow);
-
+ void listenUsingSubId(in long subId, String pkg, IPhoneStateListener callback, int events,
+ boolean notifyNow);
void notifyCallState(int state, String incomingNumber);
+ void notifyCallStateUsingSubId(in long subId, int state, String incomingNumber);
void notifyServiceState(in ServiceState state);
+ void notifyServiceStateUsingSubId(in long subId, in ServiceState state);
void notifySignalStrength(in SignalStrength signalStrength);
+ void notifySignalStrengthUsingSubId(in long subId, in SignalStrength signalStrength);
void notifyMessageWaitingChanged(boolean mwi);
+ void notifyMessageWaitingChangedUsingSubId(in long subId, boolean mwi);
void notifyCallForwardingChanged(boolean cfi);
+ void notifyCallForwardingChangedUsingSubId(in long subId, boolean cfi);
void notifyDataActivity(int state);
+ void notifyDataActivityUsingSubId(in long subId, int state);
void notifyDataConnection(int state, boolean isDataConnectivityPossible,
String reason, String apn, String apnType, in LinkProperties linkProperties,
in NetworkCapabilities networkCapabilities, int networkType, boolean roaming);
+ void notifyDataConnectionUsingSubId(long subId, int state, boolean isDataConnectivityPossible,
+ String reason, String apn, String apnType, in LinkProperties linkProperties,
+ in NetworkCapabilities networkCapabilities, int networkType, boolean roaming);
void notifyDataConnectionFailed(String reason, String apnType);
+ void notifyDataConnectionFailedUsingSubId(long subId, String reason, String apnType);
void notifyCellLocation(in Bundle cellLocation);
+ void notifyCellLocationUsingSubId(in long subId, in Bundle cellLocation);
void notifyOtaspChanged(in int otaspMode);
void notifyCellInfo(in List<CellInfo> cellInfo);
void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
@@ -47,5 +61,7 @@
void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause);
void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
String failCause);
+ void notifyCellInfoUsingSubId(in long subId, in List<CellInfo> cellInfo);
void notifyDataConnectionRealTimeInfo(in DataConnectionRealTimeInfo dcRtInfo);
+ void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 08f4379..aecf955 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -58,6 +58,7 @@
public static final int PHONE_TYPE_CDMA = RILConstants.CDMA_PHONE;
public static final int PHONE_TYPE_SIP = RILConstants.SIP_PHONE;
public static final int PHONE_TYPE_THIRD_PARTY = RILConstants.THIRD_PARTY_PHONE;
+ public static final int PHONE_TYPE_IMS = RILConstants.IMS_PHONE;
// Modes for LTE_ON_CDMA
public static final int LTE_ON_CDMA_UNKNOWN = RILConstants.LTE_ON_CDMA_UNKNOWN;
@@ -133,4 +134,55 @@
/** APN type for IA Initial Attach APN */
public static final String APN_TYPE_IA = "ia";
+ // FIXME: This looks to be used as default phoneId, rename
+ // or use SubscriptionManager.DEFAULT_SUB_ID
+ public static final int DEFAULT_SUBSCRIPTION = 0;
+
+ // FIXME: This looks to be used as invalid phoneId, rename
+ // or use SubscriptionManager.INVALID_SUB_ID
+ public static final int INVALID_SUBSCRIPTION = -1;
+
+ public static final int RIL_CARD_MAX_APPS = 8;
+
+ public static final int DEFAULT_CARD_INDEX = 0;
+
+ public static final int MAX_PHONE_COUNT_SINGLE_SIM = 1;
+
+ public static final int MAX_PHONE_COUNT_DUAL_SIM = 2;
+
+ public static final int MAX_PHONE_COUNT_TRI_SIM = 3;
+
+ public static final String SUBSCRIPTION_KEY = "subscription";
+
+ public static final String SLOT_KEY = "slot";
+
+ public static final String SUB_SETTING = "subSettings";
+
+ public static final int SUB1 = 0;
+ public static final int SUB2 = 1;
+ public static final int SUB3 = 2;
+
+ public static final int EVENT_SUBSCRIPTION_ACTIVATED = 500;
+ public static final int EVENT_SUBSCRIPTION_DEACTIVATED = 501;
+
+ // TODO: Remove these constants and use an int instead.
+ public static final int SIM_ID_1 = 0;
+ public static final int SIM_ID_2 = 1;
+ public static final int SIM_ID_3 = 2;
+ public static final int SIM_ID_4 = 3;
+
+ // ICC SIM Application Types
+ // TODO: Replace the IccCardApplicationStatus.AppType enums with these constants
+ public static final int APPTYPE_UNKNOWN = 0;
+ public static final int APPTYPE_SIM = 1;
+ public static final int APPTYPE_USIM = 2;
+ public static final int APPTYPE_RUIM = 3;
+ public static final int APPTYPE_CSIM = 4;
+ public static final int APPTYPE_ISIM = 5;
+
+ public enum CardUnavailableReason {
+ REASON_CARD_REMOVED,
+ REASON_RADIO_UNAVAILABLE,
+ REASON_SIM_REFRESH_RESET
+ };
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 815211c..0271d0a 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -57,6 +57,7 @@
retries needed */
int MISSING_RESOURCE = 16; /* no logical channel available */
int NO_SUCH_ELEMENT = 17; /* application not found on SIM */
+ int SUBSCRIPTION_NOT_SUPPORTED = 26; /* Subscription not supported */
/* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */
@@ -85,6 +86,7 @@
int CDMA_PHONE = 2;
int SIP_PHONE = 3;
int THIRD_PARTY_PHONE = 4;
+ int IMS_PHONE = 5;
int LTE_ON_CDMA_UNKNOWN = -1;
int LTE_ON_CDMA_FALSE = 0;
@@ -282,6 +284,11 @@
int RIL_REQUEST_NV_WRITE_CDMA_PRL = 120;
int RIL_REQUEST_NV_RESET_CONFIG = 121;
int RIL_REQUEST_SET_RADIO_MODE = 122;
+ int RIL_REQUEST_DATA_IDLE = 123;
+ int RIL_REQUEST_SET_UICC_SUBSCRIPTION = 124;
+ int RIL_REQUEST_ALLOW_DATA = 125;
+ int RIL_REQUEST_GET_HARDWARE_CONFIG = 126;
+ int RIL_REQUEST_ICC_SIM_AUTHENTICATION = 127;
int RIL_UNSOL_RESPONSE_BASE = 1000;
int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
@@ -322,4 +329,7 @@
int RIL_UNSOL_VOICE_RADIO_TECH_CHANGED = 1035;
int RIL_UNSOL_CELL_INFO_LIST = 1036;
int RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED = 1037;
+ int RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED = 1038;
+ int RIL_UNSOL_SRVCC_STATE_NOTIFY = 1039;
+ int RIL_UNSOL_HARDWARE_CONFIG_CHANGED = 1040;
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 9ad2d42..5954947 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -16,6 +16,8 @@
package com.android.internal.telephony;
+import android.content.Intent;
+
/**
* The intents that the telephony services broadcast.
*
@@ -48,7 +50,7 @@
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -69,7 +71,7 @@
*
* <p class="note">
* Requires no permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -88,7 +90,7 @@
*
* <p class="note">
* Requires no permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -114,7 +116,7 @@
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -136,7 +138,7 @@
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -176,7 +178,7 @@
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -207,7 +209,7 @@
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -225,7 +227,7 @@
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -243,7 +245,7 @@
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -315,4 +317,85 @@
public static final String EXTRA_PLMN = "plmn";
public static final String EXTRA_SHOW_SPN = "showSpn";
public static final String EXTRA_SPN = "spn";
+
+ /**
+ * <p>Broadcast Action: It indicates one column of a siminfo record has been changed
+ * The intent will have the following extra values:</p>
+ * <ul>
+ * <li><em>columnName</em> - The siminfo column that is updated.</li>
+ * <li><em>stringContent</em> - The string value of the updated column.</li>
+ * <li><em>intContent</em> - The int value of the updated column.</li>
+ * </ul>
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ */
+ public static final String ACTION_SIMINFO_CONTENT_CHANGE
+ = "android.intent.action.ACTION_SIMINFO_CONTENT_CHANGE";
+
+ /**
+ * <p>Broadcast Action: It indicates one column of a subinfo record has been changed
+ * The intent will have the following extra values:</p>
+ * <ul>
+ * <li><em>columnName</em> - The siminfo column that is updated.</li>
+ * <li><em>stringContent</em> - The string value of the updated column.</li>
+ * <li><em>intContent</em> - The int value of the updated column.</li>
+ * </ul>
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ */
+ public static final String ACTION_SUBINFO_CONTENT_CHANGE
+ = "android.intent.action.ACTION_SUBINFO_CONTENT_CHANGE";
+
+ /**
+ * <p>Broadcast Action: It indicates siminfo update is completed when SIM inserted state change
+ * The intent will have the following extra values:</p>
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ */
+ public static final String ACTION_SIMINFO_UPDATED
+ = "android.intent.action.ACTION_SIMINFO_UPDATED";
+
+ /**
+ * <p>Broadcast Action: It indicates subinfo record update is completed
+ * when SIM inserted state change
+ * The intent will have the following extra values:</p>
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ */
+ public static final String ACTION_SUBINFO_RECORD_UPDATED
+ = "android.intent.action.ACTION_SUBINFO_RECORD_UPDATED";
+
+ public static final String EXTRA_COLUMN_NAME = "columnName";
+ public static final String EXTRA_INT_CONTENT = "intContent";
+ public static final String EXTRA_STRING_CONTENT = "stringContent";
+
+ /**
+ * Broadcast Action: The default subscription has changed. This has the following
+ * extra values:</p>
+ * <ul>
+ * <li><em>subscription</em> - A int, the current default subscription.</li>
+ * </ul>
+ */
+ public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED
+ = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED";
+
+ /**
+ * Broadcast Action: The default data subscription has changed. This has the following
+ * extra values:</p>
+ * <ul>
+ * <li><em>subscription</em> - A int, the current data default subscription.</li>
+ * </ul>
+ */
+ public static final String ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED
+ = "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED";
+
+ /**
+ * Broadcast Action: The default voice subscription has changed. This has the following
+ * extra values:</p>
+ * <ul>
+ * <li><em>subscription</em> - A int, the current voice default subscription.</li>
+ * </ul>
+ */
+ public static final String ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED
+ = "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED";
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index f95e081..5ec4247 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -187,4 +187,26 @@
* Ignore RIL_UNSOL_NITZ_TIME_RECEIVED completely, used for debugging/testing.
*/
static final String PROPERTY_IGNORE_NITZ = "telephony.test.ignore.nitz";
+
+ /**
+ * Property to set multi sim feature.
+ * Type: String(dsds, dsda)
+ */
+ static final String PROPERTY_MULTI_SIM_CONFIG = "persist.radio.multisim.config";
+
+ /**
+ * Property to store default subscription.
+ */
+ static final String PROPERTY_DEFAULT_SUBSCRIPTION = "persist.radio.default.sub";
+
+ /**
+ * Property to enable MMS Mode.
+ * Type: string ( default = silent, enable to = prompt )
+ */
+ static final String PROPERTY_MMS_TRANSACTION = "mms.transaction";
+
+ /**
+ * Set to the sim count.
+ */
+ static final String PROPERTY_SIM_COUNT = "ro.telephony.sim.count";
}
diff --git a/tests/Camera2Tests/CameraToo/Android.mk b/tests/Camera2Tests/CameraToo/Android.mk
new file mode 100644
index 0000000..7e5911d
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/Android.mk
@@ -0,0 +1,23 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := CameraToo
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+
+include $(BUILD_PACKAGE)
diff --git a/tests/Camera2Tests/CameraToo/AndroidManifest.xml b/tests/Camera2Tests/CameraToo/AndroidManifest.xml
new file mode 100644
index 0000000..a92b5d8
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?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.example.android.camera2.cameratoo">
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application android:label="CameraToo">
+ <activity
+ android:name=".CameraTooActivity"
+ android:screenOrientation="portrait">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml b/tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml
new file mode 100644
index 0000000..f93f177
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/mainSurfaceView"
+ android:layout_height="fill_parent"
+ android:layout_width="fill_parent"
+ android:onClick="onClickOnSurfaceView" />
diff --git a/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java b/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java
new file mode 100644
index 0000000..c630bad
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java
@@ -0,0 +1,437 @@
+/*
+ * 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.example.android.camera2.cameratoo;
+
+import android.app.Activity;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.Image;
+import android.media.ImageReader;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.util.Size;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * A basic demonstration of how to write a point-and-shoot camera app against the new
+ * android.hardware.camera2 API.
+ */
+public class CameraTooActivity extends Activity {
+ /** Output files will be saved as /sdcard/Pictures/cameratoo*.jpg */
+ static final String CAPTURE_FILENAME_PREFIX = "cameratoo";
+ /** Tag to distinguish log prints. */
+ static final String TAG = "CameraToo";
+
+ /** An additional thread for running tasks that shouldn't block the UI. */
+ HandlerThread mBackgroundThread;
+ /** Handler for running tasks in the background. */
+ Handler mBackgroundHandler;
+ /** Handler for running tasks on the UI thread. */
+ Handler mForegroundHandler;
+ /** View for displaying the camera preview. */
+ SurfaceView mSurfaceView;
+ /** Used to retrieve the captured image when the user takes a snapshot. */
+ ImageReader mCaptureBuffer;
+ /** Handle to the Android camera services. */
+ CameraManager mCameraManager;
+ /** The specific camera device that we're using. */
+ CameraDevice mCamera;
+ /** Our image capture session. */
+ CameraCaptureSession mCaptureSession;
+
+ /**
+ * Given {@code choices} of {@code Size}s supported by a camera, chooses the smallest one whose
+ * width and height are at least as large as the respective requested values.
+ * @param choices The list of sizes that the camera supports for the intended output class
+ * @param width The minimum desired width
+ * @param height The minimum desired height
+ * @return The optimal {@code Size}, or an arbitrary one if none were big enough
+ */
+ static Size chooseBigEnoughSize(Size[] choices, int width, int height) {
+ // Collect the supported resolutions that are at least as big as the preview Surface
+ List<Size> bigEnough = new ArrayList<Size>();
+ for (Size option : choices) {
+ if (option.getWidth() >= width && option.getHeight() >= height) {
+ bigEnough.add(option);
+ }
+ }
+
+ // Pick the smallest of those, assuming we found any
+ if (bigEnough.size() > 0) {
+ return Collections.min(bigEnough, new CompareSizesByArea());
+ } else {
+ Log.e(TAG, "Couldn't find any suitable preview size");
+ return choices[0];
+ }
+ }
+
+ /**
+ * Compares two {@code Size}s based on their areas.
+ */
+ static class CompareSizesByArea implements Comparator<Size> {
+ @Override
+ public int compare(Size lhs, Size rhs) {
+ // We cast here to ensure the multiplications won't overflow
+ return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
+ (long) rhs.getWidth() * rhs.getHeight());
+ }
+ }
+
+ /**
+ * Called when our {@code Activity} gains focus. <p>Starts initializing the camera.</p>
+ */
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ // Start a background thread to manage camera requests
+ mBackgroundThread = new HandlerThread("background");
+ mBackgroundThread.start();
+ mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
+ mForegroundHandler = new Handler(getMainLooper());
+
+ mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
+
+ // Inflate the SurfaceView, set it as the main layout, and attach a listener
+ View layout = getLayoutInflater().inflate(R.layout.mainactivity, null);
+ mSurfaceView = (SurfaceView) layout.findViewById(R.id.mainSurfaceView);
+ mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback);
+ setContentView(mSurfaceView);
+
+ // Control flow continues in mSurfaceHolderCallback.surfaceChanged()
+ }
+
+ /**
+ * Called when our {@code Activity} loses focus. <p>Tears everything back down.</p>
+ */
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ try {
+ // Ensure SurfaceHolderCallback#surfaceChanged() will run again if the user returns
+ mSurfaceView.getHolder().setFixedSize(/*width*/0, /*height*/0);
+
+ // Cancel any stale preview jobs
+ if (mCaptureSession != null) {
+ mCaptureSession.close();
+ mCaptureSession = null;
+ }
+ } finally {
+ if (mCamera != null) {
+ mCamera.close();
+ mCamera = null;
+ }
+ }
+
+ // Finish processing posted messages, then join on the handling thread
+ mBackgroundThread.quitSafely();
+ try {
+ mBackgroundThread.join();
+ } catch (InterruptedException ex) {
+ Log.e(TAG, "Background worker thread was interrupted while joined", ex);
+ }
+
+ // Close the ImageReader now that the background thread has stopped
+ if (mCaptureBuffer != null) mCaptureBuffer.close();
+ }
+
+ /**
+ * Called when the user clicks on our {@code SurfaceView}, which has ID {@code mainSurfaceView}
+ * as defined in the {@code mainactivity.xml} layout file. <p>Captures a full-resolution image
+ * and saves it to permanent storage.</p>
+ */
+ public void onClickOnSurfaceView(View v) {
+ if (mCaptureSession != null) {
+ try {
+ CaptureRequest.Builder requester =
+ mCamera.createCaptureRequest(mCamera.TEMPLATE_STILL_CAPTURE);
+ requester.addTarget(mCaptureBuffer.getSurface());
+ try {
+ // This handler can be null because we aren't actually attaching any callback
+ mCaptureSession.capture(requester.build(), /*listener*/null, /*handler*/null);
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to file actual capture request", ex);
+ }
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to build actual capture request", ex);
+ }
+ } else {
+ Log.e(TAG, "User attempted to perform a capture outside our session");
+ }
+
+ // Control flow continues in mImageCaptureListener.onImageAvailable()
+ }
+
+ /**
+ * Callbacks invoked upon state changes in our {@code SurfaceView}.
+ */
+ final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
+ /** The camera device to use, or null if we haven't yet set a fixed surface size. */
+ private String mCameraId;
+
+ /** Whether we received a change callback after setting our fixed surface size. */
+ private boolean mGotSecondCallback;
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ // This is called every time the surface returns to the foreground
+ Log.i(TAG, "Surface created");
+ mCameraId = null;
+ mGotSecondCallback = false;
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.i(TAG, "Surface destroyed");
+ holder.removeCallback(this);
+ // We don't stop receiving callbacks forever because onResume() will reattach us
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ // On the first invocation, width and height were automatically set to the view's size
+ if (mCameraId == null) {
+ // Find the device's back-facing camera and set the destination buffer sizes
+ try {
+ for (String cameraId : mCameraManager.getCameraIdList()) {
+ CameraCharacteristics cameraCharacteristics =
+ mCameraManager.getCameraCharacteristics(cameraId);
+ if (cameraCharacteristics.get(cameraCharacteristics.LENS_FACING) ==
+ CameraCharacteristics.LENS_FACING_BACK) {
+ Log.i(TAG, "Found a back-facing camera");
+ StreamConfigurationMap info = cameraCharacteristics
+ .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ // Bigger is better when it comes to saving our image
+ Size largestSize = Collections.max(
+ Arrays.asList(info.getOutputSizes(ImageFormat.JPEG)),
+ new CompareSizesByArea());
+
+ // Prepare an ImageReader in case the user wants to capture images
+ Log.i(TAG, "Capture size: " + largestSize);
+ mCaptureBuffer = ImageReader.newInstance(largestSize.getWidth(),
+ largestSize.getHeight(), ImageFormat.JPEG, /*maxImages*/2);
+ mCaptureBuffer.setOnImageAvailableListener(
+ mImageCaptureListener, mBackgroundHandler);
+
+ // Danger, W.R.! Attempting to use too large a preview size could
+ // exceed the camera bus' bandwidth limitation, resulting in
+ // gorgeous previews but the storage of garbage capture data.
+ Log.i(TAG, "SurfaceView size: " +
+ mSurfaceView.getWidth() + 'x' + mSurfaceView.getHeight());
+ Size optimalSize = chooseBigEnoughSize(
+ info.getOutputSizes(SurfaceHolder.class), width, height);
+
+ // Set the SurfaceHolder to use the camera's largest supported size
+ Log.i(TAG, "Preview size: " + optimalSize);
+ SurfaceHolder surfaceHolder = mSurfaceView.getHolder();
+ surfaceHolder.setFixedSize(optimalSize.getWidth(),
+ optimalSize.getHeight());
+
+ mCameraId = cameraId;
+ return;
+
+ // Control flow continues with this method one more time
+ // (since we just changed our own size)
+ }
+ }
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Unable to list cameras", ex);
+ }
+
+ Log.e(TAG, "Didn't find any back-facing cameras");
+ // This is the second time the method is being invoked: our size change is complete
+ } else if (!mGotSecondCallback) {
+ if (mCamera != null) {
+ Log.e(TAG, "Aborting camera open because it hadn't been closed");
+ return;
+ }
+
+ // Open the camera device
+ try {
+ mCameraManager.openCamera(mCameraId, mCameraStateListener,
+ mBackgroundHandler);
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to configure output surface", ex);
+ }
+ mGotSecondCallback = true;
+
+ // Control flow continues in mCameraStateListener.onOpened()
+ }
+ }};
+
+ /**
+ * Calledbacks invoked upon state changes in our {@code CameraDevice}. <p>These are run on
+ * {@code mBackgroundThread}.</p>
+ */
+ final CameraDevice.StateListener mCameraStateListener =
+ new CameraDevice.StateListener() {
+ @Override
+ public void onOpened(CameraDevice camera) {
+ Log.i(TAG, "Successfully opened camera");
+ mCamera = camera;
+ try {
+ List<Surface> outputs = Arrays.asList(
+ mSurfaceView.getHolder().getSurface(), mCaptureBuffer.getSurface());
+ camera.createCaptureSession(outputs, mCaptureSessionListener,
+ mBackgroundHandler);
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to create a capture session", ex);
+ }
+
+ // Control flow continues in mCaptureSessionListener.onConfigured()
+ }
+
+ @Override
+ public void onDisconnected(CameraDevice camera) {
+ Log.e(TAG, "Camera was disconnected");
+ }
+
+ @Override
+ public void onError(CameraDevice camera, int error) {
+ Log.e(TAG, "State error on device '" + camera.getId() + "': code " + error);
+ }};
+
+ /**
+ * Callbacks invoked upon state changes in our {@code CameraCaptureSession}. <p>These are run on
+ * {@code mBackgroundThread}.</p>
+ */
+ final CameraCaptureSession.StateListener mCaptureSessionListener =
+ new CameraCaptureSession.StateListener() {
+ @Override
+ public void onConfigured(CameraCaptureSession session) {
+ Log.i(TAG, "Finished configuring camera outputs");
+ mCaptureSession = session;
+
+ SurfaceHolder holder = mSurfaceView.getHolder();
+ if (holder != null) {
+ try {
+ // Build a request for preview footage
+ CaptureRequest.Builder requestBuilder =
+ mCamera.createCaptureRequest(mCamera.TEMPLATE_PREVIEW);
+ requestBuilder.addTarget(holder.getSurface());
+ CaptureRequest previewRequest = requestBuilder.build();
+
+ // Start displaying preview images
+ try {
+ session.setRepeatingRequest(previewRequest, /*listener*/null,
+ /*handler*/null);
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to make repeating preview request", ex);
+ }
+ } catch (CameraAccessException ex) {
+ Log.e(TAG, "Failed to build preview request", ex);
+ }
+ }
+ else {
+ Log.e(TAG, "Holder didn't exist when trying to formulate preview request");
+ }
+ }
+
+ @Override
+ public void onClosed(CameraCaptureSession session) {
+ mCaptureSession = null;
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession session) {
+ Log.e(TAG, "Configuration error on device '" + mCamera.getId());
+ }};
+
+ /**
+ * Callback invoked when we've received a JPEG image from the camera.
+ */
+ final ImageReader.OnImageAvailableListener mImageCaptureListener =
+ new ImageReader.OnImageAvailableListener() {
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ // Save the image once we get a chance
+ mBackgroundHandler.post(new CapturedImageSaver(reader.acquireNextImage()));
+
+ // Control flow continues in CapturedImageSaver#run()
+ }};
+
+ /**
+ * Deferred processor responsible for saving snapshots to disk. <p>This is run on
+ * {@code mBackgroundThread}.</p>
+ */
+ static class CapturedImageSaver implements Runnable {
+ /** The image to save. */
+ private Image mCapture;
+
+ public CapturedImageSaver(Image capture) {
+ mCapture = capture;
+ }
+
+ @Override
+ public void run() {
+ try {
+ // Choose an unused filename under the Pictures/ directory
+ File file = File.createTempFile(CAPTURE_FILENAME_PREFIX, ".jpg",
+ Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_PICTURES));
+ try (FileOutputStream ostream = new FileOutputStream(file)) {
+ Log.i(TAG, "Retrieved image is" +
+ (mCapture.getFormat() == ImageFormat.JPEG ? "" : "n't") + " a JPEG");
+ ByteBuffer buffer = mCapture.getPlanes()[0].getBuffer();
+ Log.i(TAG, "Captured image size: " +
+ mCapture.getWidth() + 'x' + mCapture.getHeight());
+
+ // Write the image out to the chosen file
+ byte[] jpeg = new byte[buffer.remaining()];
+ buffer.get(jpeg);
+ ostream.write(jpeg);
+ } catch (FileNotFoundException ex) {
+ Log.e(TAG, "Unable to open output file for writing", ex);
+ } catch (IOException ex) {
+ Log.e(TAG, "Failed to write the image to the output file", ex);
+ }
+ } catch (IOException ex) {
+ Log.e(TAG, "Unable to create a new output file", ex);
+ } finally {
+ mCapture.close();
+ }
+ }
+ }
+}
diff --git a/tests/Camera2Tests/CameraToo/tests/Android.mk b/tests/Camera2Tests/CameraToo/tests/Android.mk
new file mode 100644
index 0000000..0b58243
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/tests/Android.mk
@@ -0,0 +1,25 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := CameraTooTests
+LOCAL_INSTRUMENTATION_FOR := CameraToo
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target
+
+include $(BUILD_PACKAGE)
diff --git a/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml b/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml
new file mode 100644
index 0000000..30210ba
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?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.example.android.camera2.cameratoo.tests">
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application android:label="CameraToo">
+ <uses-library android:name="android.test.runner" />
+ </application>
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.example.android.camera2.cameratoo"
+ android:label="CameraToo tests" />
+</manifest>
diff --git a/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java b/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java
new file mode 100644
index 0000000..3acca5a
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.example.android.camera2.cameratoo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.media.Image;
+import android.os.Environment;
+import android.util.Size;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.example.android.camera2.cameratoo.CameraTooActivity;
+import org.junit.Test;
+
+public class CameraTooTest {
+ private <T> void assertComparatorEq(T lhs, T rhs, Comparator<T> rel) {
+ assertEquals(String.format("%s should be equal to %s", lhs, rhs), rel.compare(lhs, rhs), 0);
+ assertEquals(String.format("%s should be equal to %s (reverse check)", lhs, rhs),
+ rel.compare(rhs, lhs), 0);
+ }
+
+ private <T> void assertComparatorLt(T lhs, T rhs, Comparator<T> rel) {
+ assertTrue(String.format("%s should be less than %s", lhs, rhs), rel.compare(lhs, rhs) < 0);
+ assertTrue(String.format("%s should be less than %s (reverse check)", lhs, rhs),
+ rel.compare(rhs, lhs) > 0);
+ }
+
+ @Test
+ public void compareSizesByArea() {
+ Size empty = new Size(0, 0), fatAndFlat = new Size(100, 0), tallAndThin = new Size(0, 100);
+ Size smallSquare = new Size(4, 4), horizRect = new Size(8, 2), vertRect = new Size(2, 8);
+ Size largeSquare = new Size(5, 5);
+ Comparator<Size> rel = new CameraTooActivity.CompareSizesByArea();
+
+ assertComparatorEq(empty, fatAndFlat, rel);
+ assertComparatorEq(empty, tallAndThin, rel);
+ assertComparatorEq(fatAndFlat, empty, rel);
+ assertComparatorEq(fatAndFlat, tallAndThin, rel);
+ assertComparatorEq(tallAndThin, empty, rel);
+ assertComparatorEq(tallAndThin, fatAndFlat, rel);
+
+ assertComparatorEq(smallSquare, horizRect, rel);
+ assertComparatorEq(smallSquare, vertRect, rel);
+ assertComparatorEq(horizRect, smallSquare, rel);
+ assertComparatorEq(horizRect, vertRect, rel);
+ assertComparatorEq(vertRect, smallSquare, rel);
+ assertComparatorEq(vertRect, horizRect, rel);
+
+ assertComparatorLt(empty, smallSquare, rel);
+ assertComparatorLt(empty, horizRect, rel);
+ assertComparatorLt(empty, vertRect, rel);
+
+ assertComparatorLt(fatAndFlat, smallSquare, rel);
+ assertComparatorLt(fatAndFlat, horizRect, rel);
+ assertComparatorLt(fatAndFlat, vertRect, rel);
+
+ assertComparatorLt(tallAndThin, smallSquare, rel);
+ assertComparatorLt(tallAndThin, horizRect, rel);
+ assertComparatorLt(tallAndThin, vertRect, rel);
+
+ assertComparatorLt(empty, largeSquare, rel);
+ assertComparatorLt(fatAndFlat, largeSquare, rel);
+ assertComparatorLt(tallAndThin, largeSquare, rel);
+ assertComparatorLt(smallSquare, largeSquare, rel);
+ assertComparatorLt(horizRect, largeSquare, rel);
+ assertComparatorLt(vertRect, largeSquare, rel);
+ }
+
+ private void assertOptimalSize(Size[] options, int minWidth, int minHeight, Size expected) {
+ Size verdict = CameraTooActivity.chooseBigEnoughSize(options, minWidth, minHeight);
+ assertEquals(String.format("Expected optimal size %s but got %s", expected, verdict),
+ verdict, expected);
+ }
+
+ @Test
+ public void chooseBigEnoughSize() {
+ Size empty = new Size(0, 0), fatAndFlat = new Size(100, 0), tallAndThin = new Size(0, 100);
+ Size smallSquare = new Size(4, 4), horizRect = new Size(8, 2), vertRect = new Size(2, 8);
+ Size largeSquare = new Size(5, 5);
+ Size[] siz =
+ { empty, fatAndFlat, tallAndThin, smallSquare, horizRect, vertRect, largeSquare };
+
+ assertOptimalSize(siz, 0, 0, empty);
+
+ assertOptimalSize(siz, 1, 0, fatAndFlat);
+ assertOptimalSize(siz, 0, 1, tallAndThin);
+
+ assertOptimalSize(siz, 4, 4, smallSquare);
+ assertOptimalSize(siz, 1, 1, smallSquare);
+ assertOptimalSize(siz, 2, 1, smallSquare);
+ assertOptimalSize(siz, 1, 2, smallSquare);
+ assertOptimalSize(siz, 3, 4, smallSquare);
+ assertOptimalSize(siz, 4, 3, smallSquare);
+
+ assertOptimalSize(siz, 8, 2, horizRect);
+ assertOptimalSize(siz, 5, 1, horizRect);
+ assertOptimalSize(siz, 5, 2, horizRect);
+
+ assertOptimalSize(siz, 2, 8, vertRect);
+ assertOptimalSize(siz, 1, 5, vertRect);
+ assertOptimalSize(siz, 2, 5, vertRect);
+
+ assertOptimalSize(siz, 5, 5, largeSquare);
+ assertOptimalSize(siz, 3, 5, largeSquare);
+ assertOptimalSize(siz, 5, 3, largeSquare);
+ }
+
+ private static final FilenameFilter OUTPUT_FILE_DECIDER = new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String filename) {
+ return filename.indexOf("cameratoo") == 0 &&
+ filename.indexOf(".jpg") == filename.length() - ".jpg".length();
+ }};
+
+ private static <T> Set<T> newlyAddedElements(Set<T> before, Set<T> after) {
+ Set<T> result = new HashSet<T>(after);
+ result.removeAll(before);
+ return result;
+ }
+
+ @Test
+ public void capturedImageSaver() throws FileNotFoundException, IOException {
+ ByteBuffer buf = ByteBuffer.allocate(25);
+ for(int index = 0; index < buf.capacity(); ++index)
+ buf.put(index, (byte) index);
+
+ Image.Plane plane = mock(Image.Plane.class);
+ when(plane.getBuffer()).thenReturn(buf);
+ when(plane.getPixelStride()).thenReturn(1);
+ when(plane.getRowStride()).thenReturn(5);
+
+ Image.Plane[] onlyPlaneThatMatters = { plane };
+ Image image = mock(Image.class);
+ when(image.getPlanes()).thenReturn(onlyPlaneThatMatters);
+ when(image.getWidth()).thenReturn(5);
+ when(image.getHeight()).thenReturn(5);
+
+ File picturesFolder =
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
+ Set<File> preListing =
+ new HashSet<File>(Arrays.asList(picturesFolder.listFiles(OUTPUT_FILE_DECIDER)));
+
+ CameraTooActivity.CapturedImageSaver saver =
+ new CameraTooActivity.CapturedImageSaver(image);
+ saver.run();
+
+ Set<File> postListing =
+ new HashSet<File>(Arrays.asList(picturesFolder.listFiles(OUTPUT_FILE_DECIDER)));
+ Set<File> newFiles = newlyAddedElements(preListing, postListing);
+
+ assertEquals(newFiles.size(), 1);
+
+ File picture = newFiles.iterator().next();
+ FileInputStream istream = new FileInputStream(picture);
+
+ for(int count = 0; count < buf.capacity(); ++count) {
+ assertEquals(istream.read(), buf.get(count));
+ }
+ assertEquals(istream.read(), -1);
+ assertTrue(picture.delete());
+ }
+}
diff --git a/tests/IdleServiceTest/Android.mk b/tests/IdleServiceTest/Android.mk
deleted file mode 100644
index a7879c5..0000000
--- a/tests/IdleServiceTest/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := IdleServiceTest
-LOCAL_CERTIFICATE := platform
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
diff --git a/tests/IdleServiceTest/AndroidManifest.xml b/tests/IdleServiceTest/AndroidManifest.xml
deleted file mode 100644
index 16d2324..0000000
--- a/tests/IdleServiceTest/AndroidManifest.xml
+++ /dev/null
@@ -1,59 +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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.idleservicetest">
-
- <application>
- <service android:name="TestService"
- android:exported="true"
- android:enabled="true"
- android:permission="android.permission.BIND_IDLE_SERVICE" >
- <intent-filter>
- <action android:name="android.service.idle.IdleService" />
- </intent-filter>
- </service>
-
- <service android:name="CrashingTestService"
- android:exported="true"
- android:enabled="true"
- android:permission="android.permission.BIND_IDLE_SERVICE" >
- <intent-filter>
- <action android:name="android.service.idle.IdleService" />
- </intent-filter>
- </service>
-
- <service android:name="TimeoutTestService"
- android:exported="true"
- android:enabled="true"
- android:permission="android.permission.BIND_IDLE_SERVICE" >
- <intent-filter>
- <action android:name="android.service.idle.IdleService" />
- </intent-filter>
- </service>
-
- <!-- UnpermissionedTestService should never run because it does
- not require the necessary permission in its <service> block -->
- <service android:name="UnpermissionedTestService"
- android:exported="true"
- android:enabled="true" >
- <intent-filter>
- <action android:name="android.service.idle.IdleService" />
- </intent-filter>
- </service>
-
- </application>
-</manifest>
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java
deleted file mode 100644
index 022ebcf..0000000
--- a/tests/IdleServiceTest/src/com/android/idleservicetest/CrashingTestService.java
+++ /dev/null
@@ -1,52 +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.idleservicetest;
-
-import android.app.maintenance.IdleService;
-import android.os.Handler;
-import android.util.Log;
-
-public class CrashingTestService extends IdleService {
- static final String TAG = "CrashingTestService";
-
- String mNull = null;
-
- @Override
- public boolean onIdleStart() {
- Log.i(TAG, "Idle maintenance: onIdleStart()");
-
- Handler h = new Handler();
- Runnable r = new Runnable() {
- @Override
- public void run() {
- Log.i(TAG, "Explicitly crashing");
- if (mNull.equals("")) {
- Log.i(TAG, "won't happen");
- }
- }
- };
- Log.i(TAG, "Posting explicit crash in 15 seconds");
- h.postDelayed(r, 15 * 1000);
- return true;
- }
-
- @Override
- public void onIdleStop() {
- Log.i(TAG, "Idle maintenance: onIdleStop()");
- }
-
-}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java
deleted file mode 100644
index 7e9805f..0000000
--- a/tests/IdleServiceTest/src/com/android/idleservicetest/TestService.java
+++ /dev/null
@@ -1,48 +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.idleservicetest;
-
-import android.app.maintenance.IdleService;
-import android.os.Handler;
-import android.util.Log;
-
-public class TestService extends IdleService {
- static final String TAG = "TestService";
-
- @Override
- public boolean onIdleStart() {
- Log.i(TAG, "Idle maintenance: onIdleStart()");
-
- Handler h = new Handler();
- Runnable r = new Runnable() {
- @Override
- public void run() {
- Log.i(TAG, "Explicitly finishing idle");
- finishIdle();
- }
- };
- Log.i(TAG, "Posting explicit finish in 15 seconds");
- h.postDelayed(r, 15 * 1000);
- return true;
- }
-
- @Override
- public void onIdleStop() {
- Log.i(TAG, "Idle maintenance: onIdleStop()");
- }
-
-}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java
deleted file mode 100644
index b2ba21b..0000000
--- a/tests/IdleServiceTest/src/com/android/idleservicetest/TimeoutTestService.java
+++ /dev/null
@@ -1,36 +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.idleservicetest;
-
-import android.app.maintenance.IdleService;
-import android.util.Log;
-
-public class TimeoutTestService extends IdleService {
- private static final String TAG = "TimeoutTestService";
-
- @Override
- public boolean onIdleStart() {
- Log.i(TAG, "onIdleStart() but anticipating time-slice timeout");
- return true;
- }
-
- @Override
- public void onIdleStop() {
- Log.i(TAG, "onIdleStop() so we're done");
- }
-
-}
diff --git a/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java b/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java
deleted file mode 100644
index b9fe32b..0000000
--- a/tests/IdleServiceTest/src/com/android/idleservicetest/UnpermissionedTestService.java
+++ /dev/null
@@ -1,38 +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.idleservicetest;
-
-import android.app.maintenance.IdleService;
-import android.util.Log;
-
-// Should never be invoked because its manifest declaration does not
-// require the necessary permission.
-public class UnpermissionedTestService extends IdleService {
- private static final String TAG = "UnpermissionedTestService";
-
- @Override
- public boolean onIdleStart() {
- Log.e(TAG, "onIdleStart() for this service should never be called!");
- return false;
- }
-
- @Override
- public void onIdleStop() {
- Log.e(TAG, "onIdleStop() for this service should never be called!");
- }
-
-}
diff --git a/tests/JobSchedulerTestApp/Android.mk b/tests/JobSchedulerTestApp/Android.mk
new file mode 100644
index 0000000..7336d8c
--- /dev/null
+++ b/tests/JobSchedulerTestApp/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := JobSchedulerTestApp
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/JobSchedulerTestApp/AndroidManifest.xml b/tests/JobSchedulerTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..9654197
--- /dev/null
+++ b/tests/JobSchedulerTestApp/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.demo.jobSchedulerApp" >
+
+ <uses-sdk
+ android:minSdkVersion="18"
+ android:targetSdkVersion="18" />
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <activity
+ android:name="com.android.demo.jobSchedulerApp.MainActivity"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <service
+ android:name=".service.TestJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ android:exported="true"/>
+ </application>
+
+</manifest>
diff --git a/tests/JobSchedulerTestApp/res/drawable-hdpi/ic_launcher.png b/tests/JobSchedulerTestApp/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a0f7005
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/JobSchedulerTestApp/res/drawable-mdpi/ic_launcher.png b/tests/JobSchedulerTestApp/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..a085462
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_action_refresh.png b/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_action_refresh.png
new file mode 100644
index 0000000..4f5d255
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_action_refresh.png
Binary files differ
diff --git a/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_launcher.png b/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..4f78eb8
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/JobSchedulerTestApp/res/drawable-xxhdpi/ic_launcher.png b/tests/JobSchedulerTestApp/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b198ee3
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/JobSchedulerTestApp/res/layout/activity_main.xml b/tests/JobSchedulerTestApp/res/layout/activity_main.xml
new file mode 100644
index 0000000..7f4961b
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/layout/activity_main.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="100dp">
+ <TextView
+ android:id="@+id/onstart_textview"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@color/none_received"
+ android:gravity="center"
+ android:text="@string/onstarttask"/>
+ <TextView
+ android:id="@+id/onstop_textview"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@color/none_received"
+ android:gravity="center"
+ android:text="@string/onstoptask"/>
+ </LinearLayout>
+ <Button
+ android:id="@+id/finished_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="20dp"
+ android:layout_marginBottom="5dp"
+ android:onClick="finishJob"
+ android:text="@string/finish_job_button_text"/>
+
+ <TextView
+ android:id="@+id/task_params"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/defaultparamtext"
+ android:gravity="center"
+ android:textSize="20dp"
+
+ android:padding="15dp"
+ android:layout_marginBottom="10dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/constraints"
+ android:textSize="18dp"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_marginLeft="10dp">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/connectivity"
+ android:layout_marginRight="10dp"/>
+ <RadioGroup
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <RadioButton android:id="@+id/checkbox_any"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/any"/>
+ <RadioButton android:id="@+id/checkbox_unmetered"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/unmetered"/>
+ </RadioGroup>
+
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/timing"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="15dp"
+ android:textSize="17dp"
+ android:text="@string/delay"/>
+ <EditText
+ android:id="@+id/delay_time"
+ android:layout_width="60dp"
+ android:layout_height="wrap_content"
+ android:inputType="number"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/deadline"
+ android:textSize="17dp"/>
+ <EditText
+ android:id="@+id/deadline_time"
+ android:layout_width="60dp"
+ android:layout_height="wrap_content"
+ android:inputType="number"/>
+ </LinearLayout>
+
+ </LinearLayout>
+ <Button
+ android:id="@+id/schedule_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="40dp"
+ android:onClick="scheduleJob"
+ android:text="@string/schedule_job_button_text"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/JobSchedulerTestApp/res/values-v11/styles.xml b/tests/JobSchedulerTestApp/res/values-v11/styles.xml
new file mode 100644
index 0000000..ff653017
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/values-v11/styles.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+</resources>
\ No newline at end of file
diff --git a/tests/JobSchedulerTestApp/res/values-v14/styles.xml b/tests/JobSchedulerTestApp/res/values-v14/styles.xml
new file mode 100644
index 0000000..a4a443a
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/values-v14/styles.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+
+ <!--
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/styles.xml and
+ res/values-v11/styles.xml on API 14+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+ <!-- API 14 theme customizations can go here. -->
+ </style>
+
+</resources>
\ No newline at end of file
diff --git a/core/res/res/layout/notification_quantum_media_action.xml b/tests/JobSchedulerTestApp/res/values/color.xml
similarity index 67%
copy from core/res/res/layout/notification_quantum_media_action.xml
copy to tests/JobSchedulerTestApp/res/values/color.xml
index 17f0848..7bd3a91 100644
--- a/core/res/res/layout/notification_quantum_media_action.xml
+++ b/tests/JobSchedulerTestApp/res/values/color.xml
@@ -14,12 +14,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-
-<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
- style="@android:style/Widget.Quantum.Light.Button.Borderless.Small"
- android:id="@+id/action0"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center"
- />
+<resources>
+ <color name="none_received">#999999</color>
+ <color name="start_received">#00FF00</color>
+ <color name="stop_received">#FF0000</color>
+</resources>
\ No newline at end of file
diff --git a/tests/JobSchedulerTestApp/res/values/strings.xml b/tests/JobSchedulerTestApp/res/values/strings.xml
new file mode 100644
index 0000000..824d4b1
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/values/strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+ <string name="onstoptask">onStopTask</string>
+ <string name="onstarttask">onStartTask</string>
+ <string name="defaultparamtext">task params will show up here.</string>
+ <string name="schedule_job_button_text">Schedule Job</string>
+ <string name="app_name">Job Scheduler Test</string>
+ <string name="finish_job_button_text">taskFinished</string>
+ <string name="manual_sync_text">Manual Sync</string>
+ <string name="constraints">Constraints</string>
+ <string name="connectivity">Connectivity:</string>
+ <string name="any">Any</string>
+ <string name="unmetered">WiFi</string>
+ <string name="timing">Timing:</string>
+ <string name="delay">Delay:</string>
+ <string name="deadline">Deadline:</string>
+</resources>
diff --git a/tests/JobSchedulerTestApp/res/values/styles.xml b/tests/JobSchedulerTestApp/res/values/styles.xml
new file mode 100644
index 0000000..43a8f2b
--- /dev/null
+++ b/tests/JobSchedulerTestApp/res/values/styles.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Light">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
+ </style>
+
+ <!-- Application theme. -->
+ <style name="AppTheme" parent="AppBaseTheme">
+ <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+ </style>
+
+</resources>
\ No newline at end of file
diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
new file mode 100644
index 0000000..15050ef
--- /dev/null
+++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.demo.jobSchedulerApp;
+
+import android.app.Activity;
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.RadioButton;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.demo.jobSchedulerApp.service.TestJobService;
+
+public class MainActivity extends Activity {
+
+ private static final String TAG = "MainActivity";
+
+ public static final int MSG_UNCOLOUR_START = 0;
+ public static final int MSG_UNCOLOUR_STOP = 1;
+ public static final int MSG_SERVICE_OBJ = 2;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ Resources res = getResources();
+ defaultColor = res.getColor(R.color.none_received);
+ startJobColor = res.getColor(R.color.start_received);
+ stopJobColor = res.getColor(R.color.stop_received);
+
+ // Set up UI.
+ mShowStartView = (TextView) findViewById(R.id.onstart_textview);
+ mShowStopView = (TextView) findViewById(R.id.onstop_textview);
+ mParamsTextView = (TextView) findViewById(R.id.task_params);
+ mDelayEditText = (EditText) findViewById(R.id.delay_time);
+ mDeadlineEditText = (EditText) findViewById(R.id.deadline_time);
+ mWiFiConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_unmetered);
+ mAnyConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_any);
+
+ mServiceComponent = new ComponentName(this, TestJobService.class);
+ // Start service and provide it a way to communicate with us.
+ Intent startServiceIntent = new Intent(this, TestJobService.class);
+ startServiceIntent.putExtra("messenger", new Messenger(mHandler));
+ startService(startServiceIntent);
+ }
+ // UI fields.
+ int defaultColor;
+ int startJobColor;
+ int stopJobColor;
+
+ TextView mShowStartView;
+ TextView mShowStopView;
+ TextView mParamsTextView;
+ EditText mDelayEditText;
+ EditText mDeadlineEditText;
+ RadioButton mWiFiConnectivityRadioButton;
+ RadioButton mAnyConnectivityRadioButton;
+ ComponentName mServiceComponent;
+ /** Service object to interact scheduled jobs. */
+ TestJobService mTestService;
+
+ private static int kJobId = 0;
+
+ Handler mHandler = new Handler(/* default looper */) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_UNCOLOUR_START:
+ mShowStartView.setBackgroundColor(defaultColor);
+ break;
+ case MSG_UNCOLOUR_STOP:
+ mShowStopView.setBackgroundColor(defaultColor);
+ break;
+ case MSG_SERVICE_OBJ:
+ mTestService = (TestJobService) msg.obj;
+ mTestService.setUiCallback(MainActivity.this);
+ }
+ }
+ };
+
+ private boolean ensureTestService() {
+ if (mTestService == null) {
+ Toast.makeText(MainActivity.this, "Service null, never got callback?",
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * UI onclick listener to schedule a job. What this job is is defined in
+ * TestJobService#scheduleJob()
+ */
+ public void scheduleJob(View v) {
+ if (!ensureTestService()) {
+ return;
+ }
+
+ JobInfo.Builder builder = new JobInfo.Builder(kJobId++, mServiceComponent);
+
+ String delay = mDelayEditText.getText().toString();
+ if (delay != null && !TextUtils.isEmpty(delay)) {
+ builder.setMinimumLatency(Long.valueOf(delay));
+ }
+ String deadline = mDeadlineEditText.getText().toString();
+ if (deadline != null && !TextUtils.isEmpty(deadline)) {
+ builder.setOverrideDeadline(Long.valueOf(deadline));
+ }
+ boolean requiresUnmetered = mWiFiConnectivityRadioButton.isSelected();
+ boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isSelected();
+ if (requiresUnmetered) {
+ builder.setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED);
+ } else if (requiresAnyConnectivity) {
+ builder.setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY);
+ }
+
+ mTestService.scheduleJob(builder.build());
+
+ }
+
+ /**
+ * UI onclick listener to call jobFinished() in our service.
+ */
+ public void finishJob(View v) {
+ if (!ensureTestService()) {
+ return;
+ }
+ mTestService.callJobFinished();
+ mParamsTextView.setText("");
+ }
+
+ public void onReceivedStartJob(JobParameters params) {
+ mShowStartView.setBackgroundColor(startJobColor);
+ Message m = Message.obtain(mHandler, MSG_UNCOLOUR_START);
+ mHandler.sendMessageDelayed(m, 1000L); // uncolour in 1 second.
+ mParamsTextView.setText("Executing: " + params.getJobId() + " " + params.getExtras());
+ }
+
+ public void onReceivedStopJob() {
+ mShowStopView.setBackgroundColor(stopJobColor);
+ Message m = Message.obtain(mHandler, MSG_UNCOLOUR_STOP);
+ mHandler.sendMessageDelayed(m, 2000L); // uncolour in 1 second.
+ mParamsTextView.setText("");
+ }
+}
diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
new file mode 100644
index 0000000..bf8e887
--- /dev/null
+++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.demo.jobSchedulerApp.service;
+
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.demo.jobSchedulerApp.MainActivity;
+
+import java.util.LinkedList;
+
+
+/**
+ * Service to handle sync requests.
+ * <p>
+ * This service is invoked in response to Intents with action android.content.SyncAdapter, and
+ * returns a Binder connection to SyncAdapter.
+ * <p>
+ * For performance, only one sync adapter will be initialized within this application's context.
+ * <p>
+ * Note: The SyncService itself is not notified when a new sync occurs. It's role is to manage the
+ * lifecycle of our and provide a handle to said SyncAdapter to the OS on
+ * request.
+ */
+public class TestJobService extends JobService {
+ private static final String TAG = "SyncService";
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.i(TAG, "Service created");
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Log.i(TAG, "Service destroyed");
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Messenger callback = intent.getParcelableExtra("messenger");
+ Message m = Message.obtain();
+ m.what = MainActivity.MSG_SERVICE_OBJ;
+ m.obj = this;
+ try {
+ callback.send(m);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error passing service object back to activity.");
+ }
+ return START_NOT_STICKY;
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ jobParamsMap.add(params);
+ if (mActivity != null) {
+ mActivity.onReceivedStartJob(params);
+ }
+ Log.i(TAG, "on start job: " + params.getJobId());
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ jobParamsMap.remove(params);
+ mActivity.onReceivedStopJob();
+ Log.i(TAG, "on stop job: " + params.getJobId());
+ return true;
+ }
+
+ MainActivity mActivity;
+ private final LinkedList<JobParameters> jobParamsMap = new LinkedList<JobParameters>();
+
+ public void setUiCallback(MainActivity activity) {
+ mActivity = activity;
+ }
+
+ /** Send job to the JobScheduler. */
+ public void scheduleJob(JobInfo t) {
+ Log.d(TAG, "Scheduling job");
+ JobScheduler tm =
+ (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ tm.schedule(t);
+ }
+
+ public boolean callJobFinished() {
+ JobParameters params = jobParamsMap.poll();
+ if (params == null) {
+ return false;
+ } else {
+ jobFinished(params, false);
+ return true;
+ }
+ }
+
+}
diff --git a/tests/TtsTests/src/com/android/speech/tts/TtsEnginesTests.java b/tests/TtsTests/src/com/android/speech/tts/TtsEnginesTests.java
new file mode 100644
index 0000000..45e5216
--- /dev/null
+++ b/tests/TtsTests/src/com/android/speech/tts/TtsEnginesTests.java
@@ -0,0 +1,64 @@
+package com.android.speech.tts;
+
+import android.speech.tts.TtsEngines;
+import android.test.InstrumentationTestCase;
+
+import java.util.Locale;
+
+public class TtsEnginesTests extends InstrumentationTestCase {
+ private TtsEngines mTtsHelper;
+
+ @Override
+ public void setUp() {
+ mTtsHelper = new TtsEngines(getInstrumentation().getContext());
+ }
+
+ public void testParseLocaleString() {
+ assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("eng-usa"));
+ assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("eng-USA"));
+ assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("en-US"));
+ assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("en_us"));
+ assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("eng_US"));
+ assertEquals(new Locale("en", "US", "foobar"),
+ mTtsHelper.parseLocaleString("eng_US-foobar"));
+ assertEquals(new Locale("en", "", "foobar"), mTtsHelper.parseLocaleString("eng__foobar"));
+ assertNull(mTtsHelper.parseLocaleString("cc_xx_barbar"));
+ assertNull(mTtsHelper.parseLocaleString("cc--barbar"));
+
+ assertEquals(new Locale("en"), mTtsHelper.parseLocaleString("eng"));
+ assertEquals(new Locale("en","US","var"), mTtsHelper.parseLocaleString("eng-USA-var"));
+ }
+
+ public void testToOldLocaleStringFormat() {
+ assertArraysEqual(new String[]{"deu", "DEU", ""},
+ TtsEngines.toOldLocaleStringFormat(new Locale("de", "DE")));
+ assertArraysEqual(new String[]{"deu", "", ""},
+ TtsEngines.toOldLocaleStringFormat(new Locale("de")));
+ assertArraysEqual(new String[]{"eng", "", ""},
+ TtsEngines.toOldLocaleStringFormat(new Locale("en")));
+ assertArraysEqual(new String[]{"eng", "USA", ""},
+ TtsEngines.toOldLocaleStringFormat(new Locale("foo")));
+ }
+
+ public void testGetLocalePrefForEngine() {
+ assertEquals(new Locale("en", "US"),
+ mTtsHelper.getLocalePrefForEngine("foo","foo:en-US"));
+ assertEquals(new Locale("en", "US"),
+ mTtsHelper.getLocalePrefForEngine("foo","foo:eng-usa"));
+ assertEquals(new Locale("en", "US"),
+ mTtsHelper.getLocalePrefForEngine("foo","foo:eng_USA"));
+ assertEquals(new Locale("de", "DE"),
+ mTtsHelper.getLocalePrefForEngine("foo","foo:deu-deu"));
+ assertEquals(Locale.getDefault(),
+ mTtsHelper.getLocalePrefForEngine("foo","foo:,bar:xx"));
+ assertEquals(Locale.getDefault(),
+ mTtsHelper.getLocalePrefForEngine("other","foo:,bar:xx"));
+ }
+
+ private void assertArraysEqual(String[] expected, String[] actual) {
+ assertEquals("array length", expected.length, actual.length);
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals("index " + i, expected[i], actual[i]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
index 113dce3..db2efc3 100644
--- a/tests/VectorDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -17,13 +17,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.test.dynamic" >
+
<uses-sdk android:minSdkVersion="20" />
<application
android:hardwareAccelerated="true"
android:label="vector" >
-
- <activity
+ <activity
android:name="VectorDrawablePerformance"
android:label="Vector Performance" >
<intent-filter>
@@ -31,13 +31,13 @@
<category android:name="com.android.test.dynamic.TEST" />
</intent-filter>
-
</activity>
<activity
android:name="VectorDrawableAnimation"
android:label="VectorTestAnimation" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
+
<category android:name="com.android.test.dynamic.TEST" />
</intent-filter>
</activity>
@@ -52,6 +52,15 @@
</intent-filter>
</activity>
<activity
+ android:name="AnimatedVectorDrawableTest"
+ android:label="AnimatedVectorDrawableTest" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="com.android.test.dynamic.TEST" />
+ </intent-filter>
+ </activity>
+ <activity
android:name="VectorDrawable01"
android:label="VectorTest1" >
<intent-filter>
@@ -68,7 +77,6 @@
<category android:name="com.android.test.dynamic.TEST" />
</intent-filter>
-
</activity>
<activity
android:name="VectorDrawableStaticPerf"
@@ -78,9 +86,7 @@
<category android:name="com.android.test.dynamic.TEST" />
</intent-filter>
-
</activity>
-
<activity
android:name="VectorCheckbox"
android:label="On a Checkbox" >
@@ -89,7 +95,6 @@
<category android:name="com.android.test.dynamic.TEST" />
</intent-filter>
-
</activity>
<activity
android:name="VectorPathChecking"
@@ -99,7 +104,6 @@
<category android:name="com.android.test.dynamic.TEST" />
</intent-filter>
-
</activity>
</application>
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml
new file mode 100644
index 0000000..d47e019
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <set android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="5000"
+ android:propertyName="trimPathEnd"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ <objectAnimator
+ android:duration="5000"
+ android:propertyName="trimPathEnd"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType" />
+ </set>
+
+</set>
\ No newline at end of file
diff --git a/core/res/res/drawable/text_select_handle_middle_quantum.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation02.xml
similarity index 67%
copy from core/res/res/drawable/text_select_handle_middle_quantum.xml
copy to tests/VectorDrawableTest/res/anim/trim_path_animation02.xml
index bff0b66..3bf2865 100644
--- a/core/res/res/drawable/text_select_handle_middle_quantum.xml
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation02.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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,6 +15,12 @@
limitations under the License.
-->
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/text_select_handle_middle_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <objectAnimator
+ android:duration="5000"
+ android:propertyName="fill"
+ android:valueFrom="#FF000000"
+ android:valueTo="#FFFF0000"/>
+
+</set>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation03.xml
similarity index 67%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to tests/VectorDrawableTest/res/anim/trim_path_animation03.xml
index fee196c..72beba2 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation03.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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,6 +15,12 @@
limitations under the License.
-->
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <objectAnimator
+ android:duration="6000"
+ android:propertyName="rotation"
+ android:valueFrom="0"
+ android:valueTo="360"/>
+
+</set>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_find_next_quantum.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation04.xml
similarity index 67%
copy from core/res/res/drawable/ic_find_next_quantum.xml
copy to tests/VectorDrawableTest/res/anim/trim_path_animation04.xml
index fee196c..ff86668 100644
--- a/core/res/res/drawable/ic_find_next_quantum.xml
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation04.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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,6 +15,12 @@
limitations under the License.
-->
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_find_next_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <objectAnimator
+ android:duration="9000"
+ android:propertyName="rotation"
+ android:valueFrom="0"
+ android:valueTo="360"/>
+
+</set>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
new file mode 100644
index 0000000..b8681b6
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
@@ -0,0 +1,36 @@
+<!--
+ 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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/vector_drawable12" >
+
+ <target
+ android:name="pie1"
+ android:animation="@anim/trim_path_animation01" />
+ <target
+ android:name="v"
+ android:animation="@anim/trim_path_animation02" />
+
+ <target
+ android:name="rotationGroup"
+ android:animation="@anim/trim_path_animation03" />
+ <target
+ android:name="rotationGroup3"
+ android:animation="@anim/trim_path_animation03" />
+ <target
+ android:name="rotationGroupBlue"
+ android:animation="@anim/trim_path_animation03" />
+
+</animated-vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
index 3042f6a..e28ec41 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -23,11 +23,15 @@
android:viewportHeight="600"
android:viewportWidth="600" />
- <group>
+ <group
+ android:name="rotationGroup"
+ android:pivotX="300.0"
+ android:pivotY="300.0"
+ android:rotation="45.0" >
<path
android:name="pie1"
- android:pathData="M300,70 a230,230 0 1,0 1,0 z"
android:fill="#00000000"
+ android:pathData="M300,70 a230,230 0 1,0 1,0 z"
android:stroke="#FF00FF00"
android:strokeWidth="70"
android:trimPathEnd=".75"
@@ -36,7 +40,66 @@
<path
android:name="v"
android:fill="#FF00FF00"
- android:pathData="M300,70 l 0,-70 70,70 -70,70z"/>
+ android:pathData="M300,70 l 0,-70 70,70 -70,70z" />
+
+ <group
+ android:name="translateToCenterGroup"
+ android:rotation="0.0"
+ android:translateX="200.0"
+ android:translateY="200.0" >
+ <path
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:stroke="#FFFF0000"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="rotationGroup2"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0" >
+ <path
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0" >
+ <group
+ android:name="rotationGroup3"
+ android:pivotX="-65.0"
+ android:pivotY="-80.0"
+ android:rotation="-45.0" >
+ <path
+ android:name="twoLines2"
+ android:fill="#FF00FF00"
+ android:pathData="@string/twoLinePathData"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="translateGroup"
+ android:translateX="65.0"
+ android:translateY="80.0" >
+ <group
+ android:name="rotationGroupBlue"
+ android:pivotX="-65.0"
+ android:pivotY="-80.0"
+ android:rotation="-45.0" >
+ <path
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:stroke="#FF0000FF"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
</group>
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
new file mode 100644
index 0000000..6e864fa
--- /dev/null
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.test.dynamic;
+
+import android.app.Activity;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+
+public class AnimatedVectorDrawableTest extends Activity {
+ private static final String LOGCAT = "VectorDrawableAnimationTest";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Button button = new Button(this);
+ button.setBackgroundResource(R.drawable.animation_vector_drawable01);
+ button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ AnimatedVectorDrawable frameAnimation = (AnimatedVectorDrawable) v.getBackground();
+ frameAnimation.start();
+ }
+ });
+
+ setContentView(button);
+ }
+}
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java
index 99de037..93b06b6 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java
@@ -14,6 +14,7 @@
package com.android.test.dynamic;
+import android.animation.ValueAnimator;
import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
@@ -27,7 +28,7 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Button button = new Button(this);
+ final Button button = new Button(this);
button.setBackgroundResource(R.drawable.animation_drawable_vector);
button.setOnClickListener(new View.OnClickListener() {
diff --git a/tests/VoiceEnrollment/Android.mk b/tests/VoiceEnrollment/Android.mk
new file mode 100644
index 0000000..2ab3d02
--- /dev/null
+++ b/tests/VoiceEnrollment/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := VoiceEnrollment
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PRIVILEGED_MODULE := true
+
+include $(BUILD_PACKAGE)
diff --git a/tests/VoiceEnrollment/AndroidManifest.xml b/tests/VoiceEnrollment/AndroidManifest.xml
new file mode 100644
index 0000000..6321222
--- /dev/null
+++ b/tests/VoiceEnrollment/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.voiceenrollment">
+
+ <application
+ android:permission="android.permission.MANAGE_VOICE_KEYPHRASES">
+ <activity android:name="TestEnrollmentActivity" android:label="Voice Enrollment Application"
+ android:theme="@android:style/Theme.Material.Light.Voice">
+ <intent-filter>
+ <action android:name="com.android.intent.action.MANAGE_VOICE_KEYPHRASES" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ <meta-data android:name="android.voice_enrollment"
+ android:resource="@xml/enrollment_application"/>
+ </application>
+</manifest>
diff --git a/core/java/android/app/task/TaskParams.aidl b/tests/VoiceEnrollment/res/xml/enrollment_application.xml
similarity index 61%
copy from core/java/android/app/task/TaskParams.aidl
copy to tests/VoiceEnrollment/res/xml/enrollment_application.xml
index 9b25855..710a0ac 100644
--- a/core/java/android/app/task/TaskParams.aidl
+++ b/tests/VoiceEnrollment/res/xml/enrollment_application.xml
@@ -1,5 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
/**
- * Copyright 2014, 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.
@@ -13,7 +15,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+-->
-package android.app.task;
-
-parcelable TaskParams;
\ No newline at end of file
+<voice-enrollment-application xmlns:android="http://schemas.android.com/apk/res/android"
+ android:searchKeyphraseId="101"
+ android:searchKeyphrase="Hello There"
+ android:searchKeyphraseSupportedLocales="en-US,en-GB,fr-FR,de-DE" />
diff --git a/core/java/android/app/task/Task.aidl b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
similarity index 76%
copy from core/java/android/app/task/Task.aidl
copy to tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
index 1f25439..7fbd965 100644
--- a/core/java/android/app/task/Task.aidl
+++ b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,10 @@
* limitations under the License.
*/
-package android.app.task;
+package com.android.test.voiceenrollment;
-parcelable Task;
-
\ No newline at end of file
+import android.app.Activity;
+
+public class TestEnrollmentActivity extends Activity {
+ // TODO(sansid): Add a test enrollment flow here.
+}
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
index e1a5854..33f000d 100644
--- a/tests/VoiceInteraction/AndroidManifest.xml
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -3,7 +3,7 @@
<application>
<activity android:name="VoiceInteractionMain" android:label="Voice Interaction"
- android:theme="@android:style/Theme.Quantum">
+ android:theme="@android:style/Theme.Material">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
@@ -24,7 +24,7 @@
android:process=":session">
</service>
<activity android:name="TestInteractionActivity" android:label="Voice Interaction Target"
- android:theme="@android:style/Theme.Quantum.Light.Voice">
+ android:theme="@android:style/Theme.Material.Light.Voice">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
index d40b05f..00c2c64 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -21,6 +21,8 @@
import android.service.voice.VoiceInteractionService;
import android.util.Log;
+import java.util.Arrays;
+
public class MainInteractionService extends VoiceInteractionService {
static final String TAG = "MainInteractionService";
@@ -28,6 +30,9 @@
public void onCreate() {
super.onCreate();
Log.i(TAG, "Creating " + this);
+ Log.i(TAG, "Keyphrase enrollment error? " + getKeyphraseEnrollmentInfo().getParseError());
+ Log.i(TAG, "Keyphrase enrollment meta-data: "
+ + Arrays.toString(getKeyphraseEnrollmentInfo().getKeyphrases()));
}
@Override
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 12d5389..2028ff4 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1457,9 +1457,9 @@
if (AaptConfig::isSameExcept(config, mconfig, ResTable_config::CONFIG_DENSITY)) {
// See if there is a better density resource
if (mconfig.density < bestDensity &&
- mconfig.density > preferredDensity &&
+ mconfig.density >= preferredDensity &&
bestDensity > preferredDensity) {
- // This density is between our best density and
+ // This density is our preferred density, or between our best density and
// the preferred density, therefore it is better.
bestDensity = mconfig.density;
} else if (mconfig.density > bestDensity &&
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index e599643..f10904c 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -166,6 +166,35 @@
ResTable_config mParams;
};
+class AnnotationProcessor {
+public:
+ AnnotationProcessor() : mDeprecated(false), mSystemApi(false) { }
+
+ void preprocessComment(String8& comment) {
+ if (comment.size() > 0) {
+ if (comment.contains("@deprecated")) {
+ mDeprecated = true;
+ }
+ if (comment.removeAll("@SystemApi")) {
+ mSystemApi = true;
+ }
+ }
+ }
+
+ void printAnnotations(FILE* fp, const char* indentStr) {
+ if (mDeprecated) {
+ fprintf(fp, "%s@Deprecated\n", indentStr);
+ }
+ if (mSystemApi) {
+ fprintf(fp, "%s@android.annotation.SystemApi\n", indentStr);
+ }
+ }
+
+private:
+ bool mDeprecated;
+ bool mSystemApi;
+};
+
// ==========================================================================
// ==========================================================================
// ==========================================================================
@@ -1742,16 +1771,13 @@
NA = idents.size();
- bool deprecated = false;
-
String16 comment = symbols->getComment(realClassName);
+ AnnotationProcessor ann;
fprintf(fp, "%s/** ", indentStr);
if (comment.size() > 0) {
String8 cmt(comment);
+ ann.preprocessComment(cmt);
fprintf(fp, "%s\n", cmt.string());
- if (strstr(cmt.string(), "@deprecated") != NULL) {
- deprecated = true;
- }
} else {
fprintf(fp, "Attributes that can be used with a %s.\n", nclassName.string());
}
@@ -1823,9 +1849,7 @@
}
fprintf(fp, "%s */\n", getIndentSpace(indent));
- if (deprecated) {
- fprintf(fp, "%s@Deprecated\n", indentStr);
- }
+ ann.printAnnotations(fp, indentStr);
fprintf(fp,
"%spublic static final int[] %s = {\n"
@@ -1871,17 +1895,14 @@
//printf("%s:%s/%s: 0x%08x\n", String8(package16).string(),
// String8(attr16).string(), String8(name16).string(), typeSpecFlags);
const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
-
- bool deprecated = false;
-
+
+ AnnotationProcessor ann;
fprintf(fp, "%s/**\n", indentStr);
if (comment.size() > 0) {
String8 cmt(comment);
+ ann.preprocessComment(cmt);
fprintf(fp, "%s <p>\n%s @attr description\n", indentStr, indentStr);
fprintf(fp, "%s %s\n", indentStr, cmt.string());
- if (strstr(cmt.string(), "@deprecated") != NULL) {
- deprecated = true;
- }
} else {
fprintf(fp,
"%s <p>This symbol is the offset where the {@link %s.R.attr#%s}\n"
@@ -1893,10 +1914,8 @@
}
if (typeComment.size() > 0) {
String8 cmt(typeComment);
+ ann.preprocessComment(cmt);
fprintf(fp, "\n\n%s %s\n", indentStr, cmt.string());
- if (strstr(cmt.string(), "@deprecated") != NULL) {
- deprecated = true;
- }
}
if (comment.size() > 0) {
if (pub) {
@@ -1915,9 +1934,7 @@
getSymbolPackage(name8, assets, pub).string(),
getSymbolName(name8).string());
fprintf(fp, "%s*/\n", indentStr);
- if (deprecated) {
- fprintf(fp, "%s@Deprecated\n", indentStr);
- }
+ ann.printAnnotations(fp, indentStr);
fprintf(fp,
"%spublic static final int %s_%s = %d;\n",
indentStr, nclassName.string(),
@@ -2056,16 +2073,14 @@
String8 name8(sym.name);
String16 comment(sym.comment);
bool haveComment = false;
- bool deprecated = false;
+ AnnotationProcessor ann;
if (comment.size() > 0) {
haveComment = true;
String8 cmt(comment);
+ ann.preprocessComment(cmt);
fprintf(fp,
"%s/** %s\n",
getIndentSpace(indent), cmt.string());
- if (strstr(cmt.string(), "@deprecated") != NULL) {
- deprecated = true;
- }
} else if (sym.isPublic && !includePrivate) {
sym.sourcePos.warning("No comment for public symbol %s:%s/%s",
assets->getPackage().string(), className.string(),
@@ -2074,6 +2089,7 @@
String16 typeComment(sym.typeComment);
if (typeComment.size() > 0) {
String8 cmt(typeComment);
+ ann.preprocessComment(cmt);
if (!haveComment) {
haveComment = true;
fprintf(fp,
@@ -2082,16 +2098,11 @@
fprintf(fp,
"%s %s\n", getIndentSpace(indent), cmt.string());
}
- if (strstr(cmt.string(), "@deprecated") != NULL) {
- deprecated = true;
- }
}
if (haveComment) {
fprintf(fp,"%s */\n", getIndentSpace(indent));
}
- if (deprecated) {
- fprintf(fp, "%s@Deprecated\n", getIndentSpace(indent));
- }
+ ann.printAnnotations(fp, getIndentSpace(indent));
fprintf(fp, id_format,
getIndentSpace(indent),
flattenSymbol(name8).string(), (int)sym.int32Val);
@@ -2107,25 +2118,21 @@
}
String8 name8(sym.name);
String16 comment(sym.comment);
- bool deprecated = false;
+ AnnotationProcessor ann;
if (comment.size() > 0) {
String8 cmt(comment);
+ ann.preprocessComment(cmt);
fprintf(fp,
"%s/** %s\n"
"%s */\n",
getIndentSpace(indent), cmt.string(),
getIndentSpace(indent));
- if (strstr(cmt.string(), "@deprecated") != NULL) {
- deprecated = true;
- }
} else if (sym.isPublic && !includePrivate) {
sym.sourcePos.warning("No comment for public symbol %s:%s/%s",
assets->getPackage().string(), className.string(),
String8(sym.name).string());
}
- if (deprecated) {
- fprintf(fp, "%s@Deprecated\n", getIndentSpace(indent));
- }
+ ann.printAnnotations(fp, getIndentSpace(indent));
fprintf(fp, "%spublic static final String %s=\"%s\";\n",
getIndentSpace(indent),
flattenSymbol(name8).string(), sym.stringVal.string());
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index cb68340..08486e6 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -16,6 +16,8 @@
LOCAL_PATH := $(my-dir)
include $(CLEAR_VARS)
+LOCAL_JAVACFLAGS := -source 6 -target 6
+
#
# Define rules to build temp_layoutlib.jar, which contains a subset of
# the classes in framework.jar. The layoutlib_create tool is used to
diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk
index e3d48fc..cfd597e 100644
--- a/tools/layoutlib/bridge/Android.mk
+++ b/tools/layoutlib/bridge/Android.mk
@@ -18,6 +18,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_JAVA_RESOURCE_DIRS := resources
+LOCAL_JAVACFLAGS := -source 6 -target 6
LOCAL_JAVA_LIBRARIES := \
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index af22f44..36102f1 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -151,7 +151,7 @@
@Override
public View inflate(int resource, ViewGroup root) {
Context context = getContext();
- if (context instanceof ContextThemeWrapper) {
+ while (context instanceof ContextThemeWrapper) {
context = ((ContextThemeWrapper) context).getBaseContext();
}
if (context instanceof BridgeContext) {
@@ -217,7 +217,7 @@
private void setupViewInContext(View view, AttributeSet attrs) {
Context context = getContext();
- if (context instanceof ContextThemeWrapper) {
+ while (context instanceof ContextThemeWrapper) {
context = ((ContextThemeWrapper) context).getBaseContext();
}
if (context instanceof BridgeContext) {
diff --git a/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
index 0dddf3d..dafc96b 100644
--- a/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
@@ -48,7 +48,7 @@
AttributeSet attrs) {
if (menuItem instanceof BridgeMenuItemImpl) {
Context context = thisInflater.getContext();
- if (context instanceof ContextThemeWrapper) {
+ while (context instanceof ContextThemeWrapper) {
context = ((ContextThemeWrapper) context).getBaseContext();
}
if (context instanceof BridgeContext) {
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
index cdb839a..8d1d0c1 100644
--- a/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
@@ -42,7 +42,7 @@
CharSequence title, int showAsAction) {
super(menu, group, id, categoryOrder, ordering, title, showAsAction);
Context context = menu.getContext();
- if (context instanceof ContextThemeWrapper) {
+ while (context instanceof ContextThemeWrapper) {
context = ((ContextThemeWrapper) context).getBaseContext();
}
if (context instanceof BridgeContext) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index 66268f2..9ec6f4d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -214,7 +214,7 @@
}
@Override
- public void notifyUserAction() throws RemoteException {
+ public void notifyUserAction(int sequenceNumber) throws RemoteException {
// TODO Auto-generated method stub
}
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 00c0f93..17d990b 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
@@ -33,6 +33,11 @@
}
@Override
+ public boolean isPowerSaveMode() throws RemoteException {
+ return false;
+ }
+
+ @Override
public IBinder asBinder() {
// pass for now.
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 09e6878..e1064b1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -197,7 +197,7 @@
}
@Override
- public void onRectangleOnScreenRequested(IBinder window, Rect rectangle, boolean immediate) {
+ public void onRectangleOnScreenRequested(IBinder window, Rect rectangle) {
// pass for now.
}
diff --git a/tools/layoutlib/create/README.txt b/tools/layoutlib/create/README.txt
index 6e0a300..32625ae 100644
--- a/tools/layoutlib/create/README.txt
+++ b/tools/layoutlib/create/README.txt
@@ -119,8 +119,8 @@
The class is then fed to RefactorClassAdapter which is like RenameClassAdapter but updates the
references in all classes. This is used to update the references of classes in the java package that
-were added in the Dalvik VM but are not a part of the standard JVM. The existing classes are
-modified to update all references to these non-standard classes. An alternate implementation of
+were added in the Dalvik VM but are not a part of the Desktop VM. The existing classes are
+modified to update all references to these non-desktop classes. An alternate implementation of
these (com.android.tools.layoutlib.java.*) is injected.
RenameClassAdapter and RefactorClassAdapter both inherit from AbstractClassAdapter which changes the
@@ -130,11 +130,15 @@
valid StackMapTable. As a side benefit of this, we can continue to support Java 6 because Java 7 on
Mac has horrible font rendering support.
+ReplaceMethodCallsAdapter replaces calls to certain methods. Currently, it only rewrites calls to
+java.lang.System.arraycopy([CI[CII)V, which is not part of the Desktop VM to call the more general
+method java.lang.System.arraycopy(Ljava/lang/Object;ILjava/lang/Object;II)V.
+
The ClassAdapters are chained together to achieve the desired output. (Look at section 2.2.7
Transformation chains in the asm user guide, link in the References.) The order of execution of
these is:
ClassReader -> [DelegateClassAdapter] -> TransformClassAdapter -> [RenameClassAdapter] ->
-RefactorClassAdapter -> ClassWriter
+RefactorClassAdapter -> [ReplaceMethodCallsAdapter] -> ClassWriter
- Method stubs
--------------
@@ -169,7 +173,7 @@
- AutoCloseable and Objects are part of Java 7. To enable us to still run on Java 6, new classes are
injected. The implementation for these classes has been taken from Android's libcore
(platform/libcore/luni/src/main/java/java/...).
-- Charsets, IntegralToString and UnsafeByteSequence are not part of the standard JAVA VM. They are
+- Charsets, IntegralToString and UnsafeByteSequence are not part of the Desktop VM. They are
added to the Dalvik VM for performance reasons. An implementation that is very close to the
original (which is at platform/libcore/luni/src/main/java/...) is injected. Since these classees
were in part of the java package, where we can't inject classes, all references to these have been
@@ -209,7 +213,7 @@
This is very similar to the Renaming classes except that it also updates the reference in all
classes. This is done for classes which are added to the Dalvik VM for performance reasons but are
-not present in the Standard Java VM. An implementation for these classes is also injected.
+not present in the Desktop VM. An implementation for these classes is also injected.
5- Method erasure based on return type
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
index 3e75c9e..8373e30 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
@@ -32,6 +32,7 @@
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -63,7 +64,8 @@
private final Set<String> mExcludedClasses;
/** Glob patterns of files to keep as is. */
private final String[] mIncludeFileGlobs;
- /** Copy these files into the output as is. */
+ /** Internal names of classes that contain method calls that need to be rewritten. */
+ private final Set<String> mReplaceMethodCallClasses = new HashSet<String>();
/**
* Creates a new analyzer.
@@ -109,6 +111,7 @@
mGen.setKeep(found);
mGen.setDeps(deps);
mGen.setCopyFiles(filesFound);
+ mGen.setRewriteMethodCallClasses(mReplaceMethodCallClasses);
}
}
@@ -118,7 +121,7 @@
*
* @param classes The map of class name => ASM ClassReader. Class names are
* in the form "android.view.View".
- * @param fileFound The map of file name => InputStream. The file name is
+ * @param filesFound The map of file name => InputStream. The file name is
* in the form "android/data/dataFile".
*/
void parseZip(List<String> jarPathList, Map<String, ClassReader> classes,
@@ -143,8 +146,8 @@
String className = classReaderToClassName(cr);
classes.put(className, cr);
} else {
- for (int i = 0; i < includeFilePatterns.length; ++i) {
- if (includeFilePatterns[i].matcher(entry.getName()).matches()) {
+ for (Pattern includeFilePattern : includeFilePatterns) {
+ if (includeFilePattern.matcher(entry.getName()).matches()) {
filesFound.put(entry.getName(), zip.getInputStream(entry));
break;
}
@@ -321,6 +324,7 @@
deps, new_deps);
for (ClassReader cr : inOutKeepClasses.values()) {
+ visitor.setClassName(cr.getClassName());
cr.accept(visitor, 0 /* flags */);
}
@@ -367,6 +371,8 @@
/** New classes to keep as-is found by this visitor. */
private final Map<String, ClassReader> mOutKeep;
+ private String mClassName;
+
/**
* Creates a new visitor that will find all the dependencies for the visited class.
* Types which are already in the zipClasses, keepClasses or inDeps are not marked.
@@ -390,6 +396,10 @@
mOutDeps = outDeps;
}
+ private void setClassName(String className) {
+ mClassName = className;
+ }
+
/**
* Considers the given class name as a dependency.
* If it does, add to the mOutDeps map.
@@ -429,7 +439,7 @@
// - android classes are added to dependencies
// - non-android classes are added to the list of classes to keep as-is (they don't need
// to be stubbed).
- if (className.indexOf("android") >= 0) { // TODO make configurable
+ if (className.contains("android")) { // TODO make configurable
mOutDeps.put(className, cr);
} else {
mOutKeep.put(className, cr);
@@ -594,7 +604,7 @@
// type and exceptions do not use generic types.
considerSignature(signature);
- return new MyMethodVisitor();
+ return new MyMethodVisitor(mClassName);
}
@Override
@@ -614,8 +624,11 @@
private class MyMethodVisitor extends MethodVisitor {
- public MyMethodVisitor() {
+ private String mOwnerClass;
+
+ public MyMethodVisitor(String ownerClass) {
super(Opcodes.ASM4);
+ mOwnerClass = ownerClass;
}
@@ -709,6 +722,13 @@
considerName(owner);
// desc is the method's descriptor (see Type).
considerDesc(desc);
+
+
+ // Check if method is java.lang.System.arrayCopy([CI[CII)V
+ if (owner.equals("java/lang/System") && name.equals("arraycopy")
+ && desc.equals("([CI[CII)V")) {
+ mReplaceMethodCallClasses.add(mOwnerClass);
+ }
}
// instruction multianewarray, whatever that is
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index 207d8ae..c96a143 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -21,7 +21,6 @@
import org.objectweb.asm.ClassWriter;
import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -55,6 +54,8 @@
private Map<String, ClassReader> mDeps;
/** All files that are to be copied as-is. */
private Map<String, InputStream> mCopyFiles;
+ /** All classes where certain method calls need to be rewritten. */
+ private Set<String> mReplaceMethodCallsClasses;
/** Counter of number of classes renamed during transform. */
private int mRenameCount;
/** FQCN Names of the classes to rename: map old-FQCN => new-FQCN */
@@ -133,7 +134,7 @@
assert i + 1 < n;
String oldFqcn = binaryToInternalClassName(refactorClasses[i]);
String newFqcn = binaryToInternalClassName(refactorClasses[i + 1]);
- mRefactorClasses.put(oldFqcn, newFqcn);;
+ mRefactorClasses.put(oldFqcn, newFqcn);
}
// create the map of renamed class -> return type of method to delete.
@@ -203,23 +204,12 @@
mCopyFiles = copyFiles;
}
- /** Gets the map of classes to output as-is, except if they have native methods */
- public Map<String, ClassReader> getKeep() {
- return mKeep;
- }
-
- /** Gets the map of dependencies that must be completely stubbed */
- public Map<String, ClassReader> getDeps() {
- return mDeps;
- }
-
- /** Gets the map of files to output as-is. */
- public Map<String, InputStream> getCopyFiles() {
- return mCopyFiles;
+ public void setRewriteMethodCallClasses(Set<String> rewriteMethodCallClasses) {
+ mReplaceMethodCallsClasses = rewriteMethodCallClasses;
}
/** Generates the final JAR */
- public void generate() throws FileNotFoundException, IOException {
+ public void generate() throws IOException {
TreeMap<String, byte[]> all = new TreeMap<String, byte[]>();
for (Class<?> clazz : mInjectClasses) {
@@ -329,14 +319,14 @@
String newName = transformName(className);
// transformName returns its input argument if there's no need to rename the class
- if (newName != className) {
+ if (!newName.equals(className)) {
mRenameCount++;
// This class is being renamed, so remove it from the list of classes not renamed.
mClassesNotRenamed.remove(className);
}
mLog.debug("Transform %s%s%s%s", className,
- newName == className ? "" : " (renamed to " + newName + ")",
+ newName.equals(className) ? "" : " (renamed to " + newName + ")",
hasNativeMethods ? " -- has natives" : "",
stubNativesOnly ? " -- stub natives only" : "");
@@ -344,8 +334,14 @@
// original class reader.
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
- ClassVisitor cv = new RefactorClassAdapter(cw, mRefactorClasses);
- if (newName != className) {
+ ClassVisitor cv = cw;
+
+ if (mReplaceMethodCallsClasses.contains(className)) {
+ cv = new ReplaceMethodCallsAdapter(cv);
+ }
+
+ cv = new RefactorClassAdapter(cv, mRefactorClasses);
+ if (!newName.equals(className)) {
cv = new RenameClassAdapter(cv, className, newName);
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index 2e952fc..ad10656 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -193,8 +193,7 @@
private static boolean processArgs(Log log, String[] args,
ArrayList<String> osJarPath, String[] osDestJar) {
boolean needs_dest = true;
- for (int i = 0; i < args.length; i++) {
- String s = args[i];
+ for (String s : args) {
if (s.equals("-v")) {
log.setVerbose(true);
} else if (s.equals("-p")) {
@@ -212,7 +211,7 @@
osJarPath.add(s);
}
} else {
- log.error("Unknow argument: %s", s);
+ log.error("Unknown argument: %s", s);
return false;
}
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
new file mode 100644
index 0000000..e57eba1
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
@@ -0,0 +1,53 @@
+/*
+ * 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.tools.layoutlib.create;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Replaces calls to certain methods that do not exist in the Desktop VM.
+ */
+public class ReplaceMethodCallsAdapter extends ClassVisitor {
+ public ReplaceMethodCallsAdapter(ClassVisitor cv) {
+ super(Opcodes.ASM4, cv);
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions) {
+ return new MyMethodVisitor(super.visitMethod(access, name, desc, signature, exceptions));
+ }
+
+ private class MyMethodVisitor extends MethodVisitor {
+
+ public MyMethodVisitor(MethodVisitor mv) {
+ super(Opcodes.ASM4, mv);
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+ // Check if method is java.lang.System.arrayCopy([CI[CII)V
+ if (owner.equals("java/lang/System") && name.equals("arraycopy")
+ && desc.equals("([CI[CII)V")) {
+ desc = "(Ljava/lang/Object;ILjava/lang/Object;II)V";
+ }
+ super.visitMethodInsn(opcode, owner, name, desc);
+ }
+ }
+}
diff --git a/tools/layoutlib/rename_font/build_font.py b/tools/layoutlib/rename_font/build_font.py
index aea3241..bd9b14c 100755
--- a/tools/layoutlib/rename_font/build_font.py
+++ b/tools/layoutlib/rename_font/build_font.py
@@ -27,7 +27,7 @@
from fontTools import ttx
import re
import os
-from lxml import etree
+import xml.etree.ElementTree as etree
import shutil
import glob
from multiprocessing import Pool
@@ -84,14 +84,13 @@
ttx.main(ttx_args)
# now parse the xml file to change its PS name.
tree = etree.parse(ttx_path)
- encoding = tree.docinfo.encoding
root = tree.getroot()
for name in root.iter('name'):
[old_ps_name, version] = get_font_info(name)
if old_ps_name is not None and version is not None:
new_ps_name = old_ps_name + version
update_name(name, new_ps_name)
- tree.write(ttx_path, xml_declaration=True, encoding=encoding )
+ tree.write(ttx_path, xml_declaration=True, encoding='utf-8' )
# generate the udpated font now.
ttx_args = ['-q', '-d', dest_dir, ttx_path]
ttx.main(ttx_args)
diff --git a/tools/layoutlib/rename_font/test.py b/tools/layoutlib/rename_font/test.py
index d4c86cb..b0b69d8 100755
--- a/tools/layoutlib/rename_font/test.py
+++ b/tools/layoutlib/rename_font/test.py
@@ -14,7 +14,7 @@
from fontTools import ttx
import os
-from lxml import etree
+import xml.etree.ElementTree as etree
import shutil
import tempfile
diff --git a/wifi/java/android/net/wifi/RssiPacketCountInfo.java b/wifi/java/android/net/wifi/RssiPacketCountInfo.java
index f549e1d..0de2033 100644
--- a/wifi/java/android/net/wifi/RssiPacketCountInfo.java
+++ b/wifi/java/android/net/wifi/RssiPacketCountInfo.java
@@ -34,14 +34,17 @@
public int txbad;
+ public int rxgood;
+
public RssiPacketCountInfo() {
- rssi = txgood = txbad = 0;
+ rssi = txgood = txbad = rxgood = 0;
}
private RssiPacketCountInfo(Parcel in) {
rssi = in.readInt();
txgood = in.readInt();
txbad = in.readInt();
+ rxgood = in.readInt();
}
@Override
@@ -49,6 +52,7 @@
out.writeInt(rssi);
out.writeInt(txgood);
out.writeInt(txbad);
+ out.writeInt(rxgood);
}
@Override
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 99151c3..8191edd 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -89,6 +89,21 @@
* {@hide}
*/
public final static int UNSPECIFIED = -1;
+ /**
+ * @hide
+ * TODO: makes real freq boundaries
+ */
+ public boolean is24GHz() {
+ return frequency > 2400 && frequency < 2500;
+ }
+
+ /**
+ * @hide
+ * TODO: makes real freq boundaries
+ */
+ public boolean is5GHz() {
+ return frequency > 4900 && frequency < 5900;
+ }
/** information element from beacon
* @hide
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 5dfc318..b64ad60 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -342,14 +342,79 @@
/**
* @hide
+ * Uid of app owning the BSSID
+ */
+ public int bssidOwnerUid;
+
+ /**
+ * @hide
* BSSID list on which this configuration was seen.
* TODO: prevent this list to grow infinitely, age-out the results
*/
public HashMap<String, ScanResult> scanResultCache;
+ /** The Below RSSI thresholds are used to configure AutoJoin
+ * - GOOD/LOW/BAD thresholds are used so as to calculate link score
+ * - UNWANTED_SOFT are used by the blacklisting logic so as to handle the unwanted network message coming from CS
+ * - UNBLACKLIST thresholds are used so as to tweak the speed at which the network is unblacklisted (i.e. if
+ * it is seen with good RSSI, it is blacklisted faster)
+ * - INITIAL_AUTOJOIN_ATTEMPT, used to determine how close from the network we need to be before autojoin kicks in
+ */
/** @hide **/
public static int INVALID_RSSI = -127;
+ /** @hide **/
+ public static int UNWANTED_BLACKLIST_SOFT_RSSI_24 = -80;
+
+ /** @hide **/
+ public static int UNWANTED_BLACKLIST_SOFT_RSSI_5 = -70;
+
+ /** @hide **/
+ public static int GOOD_RSSI_24 = -65;
+
+ /** @hide **/
+ public static int LOW_RSSI_24 = -75;
+
+ /** @hide **/
+ public static int BAD_RSSI_24 = -85;
+
+ /** @hide **/
+ public static int GOOD_RSSI_5 = -55;
+
+ /** @hide **/
+ public static int LOW_RSSI_5 = -65;
+
+ /** @hide **/
+ public static int BAD_RSSI_5 = -75;
+
+ /** @hide **/
+ public static int UNWANTED_BLACKLIST_SOFT_BUMP = 4;
+
+ /** @hide **/
+ public static int UNWANTED_BLACKLIST_HARD_BUMP = 8;
+
+ /** @hide **/
+ public static int UNBLACKLIST_THRESHOLD_24_SOFT = -75;
+
+ /** @hide **/
+ public static int UNBLACKLIST_THRESHOLD_24_HARD = -68;
+
+ /** @hide **/
+ public static int UNBLACKLIST_THRESHOLD_5_SOFT = -63;
+
+ /** @hide **/
+ public static int UNBLACKLIST_THRESHOLD_5_HARD = -56;
+
+ /** @hide **/
+ public static int INITIAL_AUTO_JOIN_ATTEMPT_MIN_24 = -80;
+
+ /** @hide **/
+ public static int INITIAL_AUTO_JOIN_ATTEMPT_MIN_5 = -70;
+
+ /** @hide
+ * 5GHz band is prefered over 2.4 if the 5GHz RSSI is higher than this threshold **/
+ public static int A_BAND_PREFERENCE_RSSI_THRESHOLD = -65;
+
/**
* @hide
* A summary of the RSSI and Band status for that configuration
@@ -426,11 +491,11 @@
if (result.seen == 0)
continue;
- if ((result.frequency > 4900) && (result.frequency < 5900)) {
+ if (result.is5GHz()) {
//strictly speaking: [4915, 5825]
//number of known BSSID on 5GHz band
status.num5 = status.num5 + 1;
- } else if ((result.frequency > 2400) && (result.frequency < 2500)) {
+ } else if (result.is24GHz()) {
//strictly speaking: [2412, 2482]
//number of known BSSID on 2.4Ghz band
status.num24 = status.num24 + 1;
@@ -438,12 +503,12 @@
if ((now_ms - result.seen) > age) continue;
- if ((result.frequency > 4900) && (result.frequency < 5900)) {
+ if (result.is5GHz()) {
if (result.level > status.rssi5) {
status.rssi5 = result.level;
status.age5 = result.seen;
}
- } else if ((result.frequency > 2400) && (result.frequency < 2500)) {
+ } else if (result.is24GHz()) {
if (result.level > status.rssi24) {
status.rssi24 = result.level;
status.age24 = result.seen;
@@ -456,7 +521,7 @@
/** @hide */
public static final int AUTO_JOIN_ENABLED = 0;
- /** @hide
+ /**
* if this is set, the WifiConfiguration cannot use linkages so as to bump
* it's relative priority.
* - status between and 128 indicate various level of blacklisting depending
@@ -465,7 +530,17 @@
* although it may have been self added we will not re-self-add it, ignore it,
* not return it to applications, and not connect to it
* */
+
+ /** @hide
+ * network was temporary disabled due to bad connection, most likely due
+ * to weak RSSI */
public static final int AUTO_JOIN_TEMPORARY_DISABLED = 1;
+ /** @hide
+ * network was temporary disabled due to bad connection, which cant be attributed
+ * to weak RSSI */
+ public static final int AUTO_JOIN_TEMPORARY_DISABLED_LINK_ERRORS = 32;
+ /** @hide */
+ public static final int AUTO_JOIN_TEMPORARY_DISABLED_AT_SUPPLICANT = 64;
/** @hide */
public static final int AUTO_JOIN_DISABLED_ON_AUTH_FAILURE = 128;
/** @hide */
@@ -476,6 +551,24 @@
*/
public int autoJoinStatus;
+
+ /**
+ * @hide
+ */
+ public long blackListTimestamp;
+
+ /**
+ * @hide
+ * last time the system was connected to this configuration.
+ */
+ public long lastConnected;
+
+ /**
+ * @hide
+ * last time the system was disconnected to this configuration.
+ */
+ public long lastDisconnected;
+
/**
* Set if the configuration was self added by the framework
* This boolean is cleared if we get a connect/save/ update or
@@ -586,7 +679,20 @@
// TODO: Add more checks
return true;
+ }
+ /**
+ * Helper function, identify if a configuration is linked
+ * @hide
+ */
+ public boolean isLinked(WifiConfiguration config) {
+ if (config.linkedConfigurations != null && linkedConfigurations != null) {
+ if (config.linkedConfigurations.get(configKey()) != null
+ && linkedConfigurations.get(config.configKey()) != null) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -614,6 +720,17 @@
return mostRecent;
}
+ /** @hide **/
+ public void setAutoJoinStatus(int status) {
+ if (status < 0) status = 0;
+ if (status == 0) {
+ blackListTimestamp = 0;
+ } else if (status > autoJoinStatus) {
+ blackListTimestamp = System.currentTimeMillis();
+ }
+ autoJoinStatus = status;
+ }
+
@Override
public String toString() {
StringBuilder sbuf = new StringBuilder();
@@ -697,6 +814,15 @@
if (selfAdded) sbuf.append("selfAdded");
if (creatorUid != 0) sbuf.append("uid=" + Integer.toString(creatorUid));
+ if (blackListTimestamp != 0) {
+ long now_ms = System.currentTimeMillis();
+ long diff = now_ms - blackListTimestamp;
+ if (diff <= 0) {
+ sbuf.append("blackListed since <incorrect>");
+ } else {
+ sbuf.append("blackListed since ").append(Long.toString(diff/1000)).append( "sec");
+ }
+ }
return sbuf.toString();
}
@@ -985,8 +1111,12 @@
didSelfAdd = source.didSelfAdd;
lastConnectUid = source.lastConnectUid;
lastUpdateUid = source.lastUpdateUid;
+ bssidOwnerUid = source.bssidOwnerUid;
creatorUid = source.creatorUid;
peerWifiConfiguration = source.peerWifiConfiguration;
+ blackListTimestamp = source.blackListTimestamp;
+ lastConnected = source.lastConnected;
+ lastDisconnected = source.lastDisconnected;
}
}
@@ -1030,17 +1160,8 @@
dest.writeInt(creatorUid);
dest.writeInt(lastConnectUid);
dest.writeInt(lastUpdateUid);
- /*
- TODO: should we write the cache results to the parcel?
- if (scanResultCache != null) {
- dest.writeInt(WifiConfiguration.SCAN_CACHE_TAG);
- dest.writeInt(scanResultCache.size());
- for (ScanResult result : scanResultCache.values()) {
- result.writeToParcel(dest, flags);
- }
- } else {
- dest.writeInt(WifiConfiguration.NOTHING_TAG);
- }*/
+ dest.writeInt(bssidOwnerUid);
+ dest.writeLong(blackListTimestamp);
}
/** Implement the Parcelable interface {@hide} */
@@ -1079,26 +1200,8 @@
config.creatorUid = in.readInt();
config.lastConnectUid = in.readInt();
config.lastUpdateUid = in.readInt();
- /*
- TODO: should we write the cache results to the parcel?
- boolean done = false;
- do {
- int tag = in.readInt();
- switch (tag) {
- case WifiConfiguration.SCAN_CACHE_TAG:
- int size = in.readInt();
- config.scanResultCache = new HashMap<String, ScanResult>();
- while (size > 0) {
- ScanResult result = ScanResult.CREATOR.createFromParcel(in);
- config.scanResultCache.put(result.BSSID, result);
- size--;
- }
- break;
- case WifiConfiguration.NOTHING_TAG:
- done = true;
- break;
- }
- } while (!done);*/
+ config.bssidOwnerUid = in.readInt();
+ config.blackListTimestamp = in.readLong();
return config;
}
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index f44cb0a..54a7df2 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -40,7 +40,7 @@
* of <code>DetailedState</code>.
*/
private static final EnumMap<SupplicantState, DetailedState> stateMap =
- new EnumMap<SupplicantState, DetailedState>(SupplicantState.class);
+ new EnumMap<SupplicantState, DetailedState>(SupplicantState.class);
static {
stateMap.put(SupplicantState.DISCONNECTED, DetailedState.DISCONNECTED);
@@ -62,14 +62,31 @@
private String mBSSID;
private WifiSsid mWifiSsid;
private int mNetworkId;
- /** Received Signal Strength Indicator */
+
+ /** @hide **/
+ public static final int INVALID_RSSI = -127;
+
+ /** @hide **/
+ public static final int MIN_RSSI = -126;
+
+ /** @hide **/
+ public static final int MAX_RSSI = 200;
+
+
+ /**
+ * Received Signal Strength Indicator
+ */
private int mRssi;
- /** Link speed in Mbps */
+ /**
+ * Link speed in Mbps
+ */
public static final String LINK_SPEED_UNITS = "Mbps";
private int mLinkSpeed;
- /** Frequency in MHz */
+ /**
+ * Frequency in MHz
+ */
public static final String FREQUENCY_UNITS = "MHz";
private int mFrequency;
@@ -77,9 +94,116 @@
private String mMacAddress;
/**
- * Flag indicating that AP has hinted that upstream connection is metered,
- * and sensitive to heavy data transfers.
+ * @hide
*/
+ public long txBad;
+ /**
+ * @hide
+ */
+ public long txRetries;
+ /**
+ * @hide
+ */
+ public long txSuccess;
+ /**
+ * @hide
+ */
+ public long rxSuccess;
+ /**
+ * @hide
+ */
+ public double txBadRate;
+ /**
+ * @hide
+ */
+ public double txRetriesRate;
+ /**
+ * @hide
+ */
+ public double txSuccessRate;
+ /**
+ * @hide
+ */
+ public double rxSuccessRate;
+
+ /**
+ * @hide
+ */
+ public int badRssiCount;
+
+ /**
+ * @hide
+ */
+ public int lowRssiCount;
+
+ /**
+ * @hide
+ */
+ public int score;
+
+ /**
+ * TODO: get actual timestamp and calculate true rates
+ * @hide
+ */
+ public void updatePacketRates(WifiLinkLayerStats stats) {
+ if (stats != null) {
+ long txgood = stats.txmpdu_be + stats.txmpdu_bk + stats.txmpdu_vi + stats.txmpdu_vo;
+ long txretries = stats.retries_be + stats.retries_bk
+ + stats.retries_vi + stats.retries_vo;
+ long rxgood = stats.rxmpdu_be + stats.rxmpdu_bk + stats.rxmpdu_vi + stats.rxmpdu_vo;
+ long txbad = stats.lostmpdu_be + stats.lostmpdu_bk
+ + stats.lostmpdu_vi + stats.lostmpdu_vo;
+
+ txBadRate = (txBadRate * 0.5)
+ + ((double) (txbad - txBad) * 0.5);
+ txSuccessRate = (txSuccessRate * 0.5)
+ + ((double) (txgood - txSuccess) * 0.5);
+ rxSuccessRate = (rxSuccessRate * 0.5)
+ + ((double) (rxgood - rxSuccess) * 0.5);
+ txRetriesRate = (txRetriesRate * 0.5)
+ + ((double) (txretries - txRetries) * 0.5);
+
+ txBad = txbad;
+ txSuccess = txgood;
+ rxSuccess = rxgood;
+ txRetries = txretries;
+ } else {
+ txBad = 0;
+ txSuccess = 0;
+ rxSuccess = 0;
+ txRetries = 0;
+ txBadRate = 0;
+ txSuccessRate = 0;
+ rxSuccessRate = 0;
+ txRetriesRate = 0;
+ }
+ }
+
+
+ /**
+ * This function is less powerful and used if the WifiLinkLayerStats API is not implemented
+ * at the Wifi HAL
+ * @hide
+ */
+ public void updatePacketRates(long txPackets, long rxPackets) {
+ //paranoia
+ txBad = 0;
+ txRetries = 0;
+ txBadRate = 0;
+ txRetriesRate = 0;
+
+ txSuccessRate = (txSuccessRate * 0.5)
+ + ((double) (txPackets - txSuccess) * 0.5);
+ rxSuccessRate = (rxSuccessRate * 0.5)
+ + ((double) (rxPackets - rxSuccess) * 0.5);
+ txSuccess = txPackets;
+ rxSuccess = rxPackets;
+ }
+
+ /**
+ * Flag indicating that AP has hinted that upstream connection is metered,
+ * and sensitive to heavy data transfers.
+ */
private boolean mMeteredHint;
/** @hide */
@@ -88,11 +212,34 @@
mBSSID = null;
mNetworkId = -1;
mSupplicantState = SupplicantState.UNINITIALIZED;
- mRssi = -9999;
+ mRssi = INVALID_RSSI;
mLinkSpeed = -1;
mFrequency = -1;
}
+ /** @hide */
+ public void reset() {
+ setInetAddress(null);
+ setBSSID(null);
+ setSSID(null);
+ setNetworkId(-1);
+ setRssi(INVALID_RSSI);
+ setLinkSpeed(-1);
+ setFrequency(-1);
+ setMeteredHint(false);
+ txBad = 0;
+ txSuccess = 0;
+ rxSuccess = 0;
+ txRetries = 0;
+ txBadRate = 0;
+ txSuccessRate = 0;
+ rxSuccessRate = 0;
+ txRetriesRate = 0;
+ lowRssiCount = 0;
+ badRssiCount = 0;
+ score = 0;
+ }
+
/**
* Copy constructor
* @hide
@@ -109,6 +256,17 @@
mIpAddress = source.mIpAddress;
mMacAddress = source.mMacAddress;
mMeteredHint = source.mMeteredHint;
+ txBad = source.txBad;
+ txRetries = source.txRetries;
+ txSuccess = source.txSuccess;
+ rxSuccess = source.rxSuccess;
+ txBadRate = source.txBadRate;
+ txRetriesRate = source.txRetriesRate;
+ txSuccessRate = source.txSuccessRate;
+ rxSuccessRate = source.rxSuccessRate;
+ score = source.score;
+ badRssiCount = source.badRssiCount;
+ lowRssiCount = source.lowRssiCount;
}
}
@@ -158,7 +316,7 @@
/**
* Returns the received signal strength indicator of the current 802.11
* network, in dBm.
- * @return the RSSI, in the range -110 to 10
+ * @return the RSSI, in the range -127 to 200
*/
public int getRssi() {
return mRssi;
@@ -166,6 +324,10 @@
/** @hide */
public void setRssi(int rssi) {
+ if (rssi < INVALID_RSSI)
+ rssi = INVALID_RSSI;
+ if (rssi > MAX_RSSI)
+ rssi = MAX_RSSI;
mRssi = rssi;
}
@@ -198,6 +360,22 @@
}
/**
+ * @hide
+ * TODO: makes real freq boundaries
+ */
+ public boolean is24GHz() {
+ return mFrequency < 4000;
+ }
+
+ /**
+ * @hide
+ * TODO: makes real freq boundaries
+ */
+ public boolean is5GHz() {
+ return mFrequency > 4000;
+ }
+
+ /**
* Record the MAC address of the WLAN interface
* @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
* @hide
@@ -325,8 +503,8 @@
append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS).
append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS).
append(", Net ID: ").append(mNetworkId).
- append(", Metered hint: ").append(mMeteredHint);
-
+ append(", Metered hint: ").append(mMeteredHint).
+ append(", score: ").append(Integer.toString(score));
return sb.toString();
}
@@ -356,6 +534,13 @@
dest.writeString(mBSSID);
dest.writeString(mMacAddress);
dest.writeInt(mMeteredHint ? 1 : 0);
+ dest.writeInt(score);
+ dest.writeDouble(txSuccessRate);
+ dest.writeDouble(txRetriesRate);
+ dest.writeDouble(txBadRate);
+ dest.writeDouble(rxSuccessRate);
+ dest.writeInt(badRssiCount);
+ dest.writeInt(lowRssiCount);
mSupplicantState.writeToParcel(dest, flags);
}
@@ -379,6 +564,13 @@
info.mBSSID = in.readString();
info.mMacAddress = in.readString();
info.mMeteredHint = in.readInt() != 0;
+ info.score = in.readInt();
+ info.txSuccessRate = in.readDouble();
+ info.txRetriesRate = in.readDouble();
+ info.txBadRate = in.readDouble();
+ info.rxSuccessRate = in.readDouble();
+ info.badRssiCount = in.readInt();
+ info.lowRssiCount = in.readInt();
info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
return info;
}
diff --git a/wifi/java/android/net/wifi/WifiLinkLayerStats.java b/wifi/java/android/net/wifi/WifiLinkLayerStats.java
index 922eddd..ae2fa98 100644
--- a/wifi/java/android/net/wifi/WifiLinkLayerStats.java
+++ b/wifi/java/android/net/wifi/WifiLinkLayerStats.java
@@ -111,6 +111,8 @@
/** {@hide} */
public String toString() {
StringBuilder sbuf = new StringBuilder();
+ sbuf.append(" WifiLinkLayerStats: ").append('\n');
+
if (this.SSID != null) {
sbuf.append(" SSID: ").append(this.SSID).append('\n');
}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 3b65ca8..21b700d 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -153,12 +153,17 @@
dest.writeInt(band);
dest.writeInt(periodInMs);
dest.writeInt(reportEvents);
- dest.writeInt(channels.length);
- for (int i = 0; i < channels.length; i++) {
- dest.writeInt(channels[i].frequency);
- dest.writeInt(channels[i].dwellTimeMS);
- dest.writeInt(channels[i].passive ? 1 : 0);
+ if (channels != null) {
+ dest.writeInt(channels.length);
+
+ for (int i = 0; i < channels.length; i++) {
+ dest.writeInt(channels[i].frequency);
+ dest.writeInt(channels[i].dwellTimeMS);
+ dest.writeInt(channels[i].passive ? 1 : 0);
+ }
+ } else {
+ dest.writeInt(0);
}
}
@@ -211,10 +216,14 @@
/** Implement the Parcelable interface {@hide} */
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mResults.length);
- for (int i = 0; i < mResults.length; i++) {
- ScanResult result = mResults[i];
- result.writeToParcel(dest, flags);
+ if (mResults != null) {
+ dest.writeInt(mResults.length);
+ for (int i = 0; i < mResults.length; i++) {
+ ScanResult result = mResults[i];
+ result.writeToParcel(dest, flags);
+ }
+ } else {
+ dest.writeInt(0);
}
}
@@ -324,13 +333,17 @@
dest.writeInt(unchangedSampleSize);
dest.writeInt(minApsBreachingThreshold);
dest.writeInt(periodInMs);
- dest.writeInt(hotspotInfos.length);
- for (int i = 0; i < hotspotInfos.length; i++) {
- HotspotInfo info = hotspotInfos[i];
- dest.writeString(info.bssid);
- dest.writeInt(info.low);
- dest.writeInt(info.high);
- dest.writeInt(info.frequencyHint);
+ if (hotspotInfos != null) {
+ dest.writeInt(hotspotInfos.length);
+ for (int i = 0; i < hotspotInfos.length; i++) {
+ HotspotInfo info = hotspotInfos[i];
+ dest.writeString(info.bssid);
+ dest.writeInt(info.low);
+ dest.writeInt(info.high);
+ dest.writeInt(info.frequencyHint);
+ }
+ } else {
+ dest.writeInt(0);
}
}
@@ -456,13 +469,18 @@
/** Implement the Parcelable interface {@hide} */
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(apLostThreshold);
- dest.writeInt(hotspotInfos.length);
- for (int i = 0; i < hotspotInfos.length; i++) {
- HotspotInfo info = hotspotInfos[i];
- dest.writeString(info.bssid);
- dest.writeInt(info.low);
- dest.writeInt(info.high);
- dest.writeInt(info.frequencyHint);
+
+ if (hotspotInfos != null) {
+ dest.writeInt(hotspotInfos.length);
+ for (int i = 0; i < hotspotInfos.length; i++) {
+ HotspotInfo info = hotspotInfos[i];
+ dest.writeString(info.bssid);
+ dest.writeInt(info.low);
+ dest.writeInt(info.high);
+ dest.writeInt(info.frequencyHint);
+ }
+ } else {
+ dest.writeInt(0);
}
}
@@ -680,6 +698,42 @@
}
}
+ /** @hide */
+ public static class OperationResult implements Parcelable {
+ public int reason;
+ public String description;
+
+ public OperationResult(int reason, String description) {
+ this.reason = reason;
+ this.description = description;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(reason);
+ dest.writeString(description);
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<OperationResult> CREATOR =
+ new Creator<OperationResult>() {
+ public OperationResult createFromParcel(Parcel in) {
+ int reason = in.readInt();
+ String description = in.readString();
+ return new OperationResult(reason, description);
+ }
+
+ public OperationResult[] newArray(int size) {
+ return new OperationResult[size];
+ }
+ };
+ }
+
private static class ServiceHandler extends Handler {
ServiceHandler(Looper looper) {
super(looper);
@@ -717,9 +771,11 @@
case CMD_OP_SUCCEEDED :
((ActionListener) listener).onSuccess();
break;
- case CMD_OP_FAILED :
- ((ActionListener) listener).onFailure(msg.arg1, (String)msg.obj);
- removeListener(msg.arg2);
+ case CMD_OP_FAILED : {
+ OperationResult result = (OperationResult)msg.obj;
+ ((ActionListener) listener).onFailure(result.reason, result.description);
+ removeListener(msg.arg2);
+ }
break;
case CMD_SCAN_RESULT :
((ScanListener) listener).onResults(
diff --git a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
index 8375d09..61c2b8a 100644
--- a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
@@ -16,6 +16,8 @@
package android.net.wifi.passpoint;
+import android.net.wifi.ScanResult;
+import android.net.wifi.passpoint.WifiPasspointPolicy;
import android.os.Messenger;
/**
@@ -27,5 +29,6 @@
{
Messenger getMessenger();
int getPasspointState();
+ List<WifiPasspointPolicy> requestCredentialMatch(in List<ScanResult> requested);
}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
index 54ac71e..33ccad5 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
@@ -493,7 +493,8 @@
}
if (this.mType.equals("TLS")) {
result = this.mRealm.equals(other.mRealm) &&
- this.mHomeSpFqdn.equals(other.mHomeSpFqdn);
+ this.mHomeSpFqdn.equals(other.mHomeSpFqdn) &&
+ this.mClientCert.equals(other.mClientCert);
}
if (this.mType.equals("SIM")) {
result = this.mMcc.equals(other.mMcc) &&
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
index 8ab5c1e..33db3f5 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
@@ -213,22 +213,22 @@
public String venueName;
/** list of network authentication types */
- public List<NetworkAuthType> networkAuthType;
+ public List<NetworkAuthType> networkAuthTypeList;
/** list of roaming consortium OIs */
- public List<String> roamingConsortium;
+ public List<String> roamingConsortiumList;
/** IP address availability */
public IpAddressType ipAddrTypeAvailability;
- /** NAI realm */
- public List<NaiRealm> naiRealm;
+ /** list of NAI realm */
+ public List<NaiRealm> naiRealmList;
- /** 3GPP cellular network */
- public List<CellularNetwork> cellularNetwork;
+ /** list of 3GPP cellular network */
+ public List<CellularNetwork> cellularNetworkList;
- /** fully qualified domain name (FQDN) */
- public List<String> domainName;
+ /** list of fully qualified domain name (FQDN) */
+ public List<String> domainNameList;
/** HS 2.0 operator friendly name */
public String operatorFriendlyName;
@@ -236,10 +236,10 @@
/** HS 2.0 wan metrics */
public WanMetrics wanMetrics;
- /** HS 2.0 list of IP proto port */
- public List<IpProtoPort> connectionCapability;
+ /** list of HS 2.0 IP proto port */
+ public List<IpProtoPort> connectionCapabilityList;
- /** HS 2.0 list of OSU providers */
+ /** list of HS 2.0 OSU providers */
public List<WifiPasspointOsuProvider> osuProviderList;
/**
@@ -286,20 +286,21 @@
public String toString() {
StringBuffer sb = new StringBuffer();
- sb.append("BSSID: ").append(bssid);
+ sb.append("BSSID: ").append("(").append(bssid).append(")");
if (venueName != null)
- sb.append(" venueName: ").append(venueName.replace("\n", "\\n"));
+ sb.append(" venueName: ").append("(")
+ .append(venueName.replace("\n", "\\n")).append(")");
- if (networkAuthType != null) {
+ if (networkAuthTypeList != null) {
sb.append(" networkAuthType: ");
- for (NetworkAuthType auth : networkAuthType)
+ for (NetworkAuthType auth : networkAuthTypeList)
sb.append("(").append(auth.toString()).append(")");
}
- if (roamingConsortium != null) {
+ if (roamingConsortiumList != null) {
sb.append(" roamingConsortium: ");
- for (String oi : roamingConsortium)
+ for (String oi : roamingConsortiumList)
sb.append("(").append(oi).append(")");
}
@@ -308,21 +309,21 @@
.append(ipAddrTypeAvailability.toString()).append(")");
}
- if (naiRealm != null) {
+ if (naiRealmList != null) {
sb.append(" naiRealm: ");
- for (NaiRealm realm : naiRealm)
+ for (NaiRealm realm : naiRealmList)
sb.append("(").append(realm.toString()).append(")");
}
- if (cellularNetwork != null) {
+ if (cellularNetworkList != null) {
sb.append(" cellularNetwork: ");
- for (CellularNetwork plmn : cellularNetwork)
+ for (CellularNetwork plmn : cellularNetworkList)
sb.append("(").append(plmn.toString()).append(")");
}
- if (domainName != null) {
+ if (domainNameList != null) {
sb.append(" domainName: ");
- for (String fqdn : domainName)
+ for (String fqdn : domainNameList)
sb.append("(").append(fqdn).append(")");
}
@@ -334,9 +335,9 @@
sb.append(" wanMetrics: ").append("(")
.append(wanMetrics.toString()).append(")");
- if (connectionCapability != null) {
+ if (connectionCapabilityList != null) {
sb.append(" connectionCapability: ");
- for (IpProtoPort ip : connectionCapability)
+ for (IpProtoPort ip : connectionCapabilityList)
sb.append("(").append(ip.toString()).append(")");
}
@@ -355,21 +356,21 @@
out.writeString(bssid);
out.writeString(venueName);
- if (networkAuthType == null) {
+ if (networkAuthTypeList == null) {
out.writeInt(0);
} else {
- out.writeInt(networkAuthType.size());
- for (NetworkAuthType auth : networkAuthType) {
+ out.writeInt(networkAuthTypeList.size());
+ for (NetworkAuthType auth : networkAuthTypeList) {
out.writeInt(auth.type);
out.writeString(auth.redirectUrl);
}
}
- if (roamingConsortium == null) {
+ if (roamingConsortiumList == null) {
out.writeInt(0);
} else {
- out.writeInt(roamingConsortium.size());
- for (String oi : roamingConsortium)
+ out.writeInt(roamingConsortiumList.size());
+ for (String oi : roamingConsortiumList)
out.writeString(oi);
}
@@ -379,32 +380,32 @@
out.writeInt(ipAddrTypeAvailability.availability);
}
- if (naiRealm == null) {
+ if (naiRealmList == null) {
out.writeInt(0);
} else {
- out.writeInt(naiRealm.size());
- for (NaiRealm realm : naiRealm) {
+ out.writeInt(naiRealmList.size());
+ for (NaiRealm realm : naiRealmList) {
out.writeInt(realm.encoding);
out.writeString(realm.realm);
}
}
- if (cellularNetwork == null) {
+ if (cellularNetworkList == null) {
out.writeInt(0);
} else {
- out.writeInt(cellularNetwork.size());
- for (CellularNetwork plmn : cellularNetwork) {
+ out.writeInt(cellularNetworkList.size());
+ for (CellularNetwork plmn : cellularNetworkList) {
out.writeString(plmn.mcc);
out.writeString(plmn.mnc);
}
}
- if (domainName == null) {
+ if (domainNameList == null) {
out.writeInt(0);
} else {
- out.writeInt(domainName.size());
- for (String fqdn : domainName)
+ out.writeInt(domainNameList.size());
+ for (String fqdn : domainNameList)
out.writeString(fqdn);
}
@@ -422,11 +423,11 @@
out.writeInt(wanMetrics.lmd);
}
- if (connectionCapability == null) {
+ if (connectionCapabilityList == null) {
out.writeInt(0);
} else {
- out.writeInt(connectionCapability.size());
- for (IpProtoPort ip : connectionCapability) {
+ out.writeInt(connectionCapabilityList.size());
+ for (IpProtoPort ip : connectionCapabilityList) {
out.writeInt(ip.proto);
out.writeInt(ip.port);
out.writeInt(ip.status);
@@ -461,20 +462,20 @@
n = in.readInt();
if (n > 0) {
- p.networkAuthType = new ArrayList<NetworkAuthType>();
+ p.networkAuthTypeList = new ArrayList<NetworkAuthType>();
for (int i = 0; i < n; i++) {
NetworkAuthType auth = new NetworkAuthType();
auth.type = in.readInt();
auth.redirectUrl = in.readString();
- p.networkAuthType.add(auth);
+ p.networkAuthTypeList.add(auth);
}
}
n = in.readInt();
if (n > 0) {
- p.roamingConsortium = new ArrayList<String>();
+ p.roamingConsortiumList = new ArrayList<String>();
for (int i = 0; i < n; i++)
- p.roamingConsortium.add(in.readString());
+ p.roamingConsortiumList.add(in.readString());
}
n = in.readInt();
@@ -485,31 +486,31 @@
n = in.readInt();
if (n > 0) {
- p.naiRealm = new ArrayList<NaiRealm>();
+ p.naiRealmList = new ArrayList<NaiRealm>();
for (int i = 0; i < n; i++) {
NaiRealm realm = new NaiRealm();
realm.encoding = in.readInt();
realm.realm = in.readString();
- p.naiRealm.add(realm);
+ p.naiRealmList.add(realm);
}
}
n = in.readInt();
if (n > 0) {
- p.cellularNetwork = new ArrayList<CellularNetwork>();
+ p.cellularNetworkList = new ArrayList<CellularNetwork>();
for (int i = 0; i < n; i++) {
CellularNetwork plmn = new CellularNetwork();
plmn.mcc = in.readString();
plmn.mnc = in.readString();
- p.cellularNetwork.add(plmn);
+ p.cellularNetworkList.add(plmn);
}
}
n = in.readInt();
if (n > 0) {
- p.domainName = new ArrayList<String>();
+ p.domainNameList = new ArrayList<String>();
for (int i = 0; i < n; i++)
- p.domainName.add(in.readString());
+ p.domainNameList.add(in.readString());
}
p.operatorFriendlyName = in.readString();
@@ -527,13 +528,13 @@
n = in.readInt();
if (n > 0) {
- p.connectionCapability = new ArrayList<IpProtoPort>();
+ p.connectionCapabilityList = new ArrayList<IpProtoPort>();
for (int i = 0; i < n; i++) {
IpProtoPort ip = new IpProtoPort();
ip.proto = in.readInt();
ip.port = in.readInt();
ip.status = in.readInt();
- p.connectionCapability.add(ip);
+ p.connectionCapabilityList.add(ip);
}
}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
index 55acbad..e7e6767 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
@@ -22,6 +22,8 @@
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
@@ -45,58 +47,53 @@
/* Passpoint states values */
- /** Passpoint is in an known state. This should only occur in boot time @hide */
+ /** Passpoint is in an unknown state. This should only occur in boot time */
public static final int PASSPOINT_STATE_UNKNOWN = 0;
- /** Passpoint is disabled. This occurs when wifi is disabled. @hide */
+ /** Passpoint is disabled. This occurs when wifi is disabled */
public static final int PASSPOINT_STATE_DISABLED = 1;
- /** Passpoint is enabled and in discovery state. @hide */
+ /** Passpoint is enabled and in discovery state */
public static final int PASSPOINT_STATE_DISCOVERY = 2;
- /** Passpoint is enabled and in access state. @hide */
+ /** Passpoint is enabled and in access state */
public static final int PASSPOINT_STATE_ACCESS = 3;
- /** Passpoint is enabled and in provisioning state. @hide */
+ /** Passpoint is enabled and in provisioning state */
public static final int PASSPOINT_STATE_PROVISION = 4;
/* Passpoint callback error codes */
- /** Indicates that the operation failed due to an internal error @hide */
- public static final int ERROR = 0;
+ /** Indicates that the operation failed due to an internal error */
+ public static final int REASON_ERROR = 0;
- /** Indicates that the operation failed because wifi is disabled @hide */
- public static final int WIFI_DISABLED = 1;
+ /** Indicates that the operation failed because wifi is disabled */
+ public static final int REASON_WIFI_DISABLED = 1;
- /** Indicates that the operation failed because the framework is busy @hide */
- public static final int BUSY = 2;
+ /** Indicates that the operation failed because the framework is busy */
+ public static final int REASON_BUSY = 2;
+
+ /** Indicates that the operation failed because parameter is invalid */
+ public static final int REASON_INVALID_PARAMETER = 3;
+
+ /** Indicates that the operation failed because the server is not trusted */
+ public static final int REASON_NOT_TRUSTED = 4;
/**
* protocol supported for Passpoint
- * @hide
*/
public static final String PROTOCOL_DM = "OMA-DM-ClientInitiated";
/**
* protocol supported for Passpoint
- * @hide
*/
public static final String PROTOCOL_SOAP = "SPP-ClientInitiated";
/* Passpoint broadcasts */
/**
- * Broadcast intent action indicating that Passpoint online sign up is
- * avaiable.
- * @hide
- */
- public static final String PASSPOINT_OSU_AVAILABLE =
- "android.net.wifi.passpoint.OSU_AVAILABLE";
-
- /**
* Broadcast intent action indicating that the state of Passpoint
* connectivity has changed
- * @hide
*/
public static final String PASSPOINT_STATE_CHANGED_ACTION =
"android.net.wifi.passpoint.STATE_CHANGE";
@@ -104,7 +101,6 @@
/**
* Broadcast intent action indicating that the saved Passpoint credential
* list has changed
- * @hide
*/
public static final String PASSPOINT_CRED_CHANGED_ACTION =
"android.net.wifi.passpoint.CRED_CHANGE";
@@ -112,21 +108,18 @@
/**
* Broadcast intent action indicating that Passpoint online sign up is
* avaiable.
- * @hide
*/
public static final String PASSPOINT_OSU_AVAILABLE_ACTION =
"android.net.wifi.passpoint.OSU_AVAILABLE";
/**
* Broadcast intent action indicating that user remediation is required
- * @hide
*/
public static final String PASSPOINT_USER_REM_REQ_ACTION =
"android.net.wifi.passpoint.USER_REM_REQ";
/**
* Interface for callback invocation when framework channel is lost
- * @hide
*/
public interface ChannelListener {
/**
@@ -138,14 +131,13 @@
/**
* Interface for callback invocation on an application action
- * @hide
*/
public interface ActionListener {
/** The operation succeeded */
public void onSuccess();
/**
- * * The operation failed
+ * The operation failed
*
* @param reason The reason for failure could be one of
* {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
@@ -155,7 +147,6 @@
/**
* Interface for callback invocation when doing OSU or user remediation
- * @hide
*/
public interface OsuRemListener {
/** The operation succeeded */
@@ -171,11 +162,11 @@
/**
* Browser launch is requried for user interaction. When this callback
- * is called, app should launch browser / webview to the given URL.
+ * is called, app should launch browser / webview to the given URI.
*
- * @param url URL for browser launch
+ * @param uri URI for browser launch
*/
- public void onBrowserLaunch(String url);
+ public void onBrowserLaunch(String uri);
/**
* When this is called, app should dismiss the previously lanched browser.
@@ -187,7 +178,6 @@
* A channel that connects the application to the wifi passpoint framework.
* Most passpoint operations require a Channel as an argument.
* An instance of Channel is obtained by doing a call on {@link #initialize}
- * @hide
*/
public static class Channel {
private final static int INVALID_LISTENER_KEY = 0;
@@ -288,7 +278,8 @@
@Override
public void handleMessage(Message message) {
- Object listener = getListener(message.arg2, false);
+ Object listener = null;
+
switch (message.what) {
case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
if (mChannelListener != null) {
@@ -300,6 +291,7 @@
case REQUEST_ANQP_INFO_SUCCEEDED:
WifiPasspointInfo result = (WifiPasspointInfo) message.obj;
anqpRequestFinish(result);
+ listener = getListener(message.arg2, false);
if (listener != null) {
((ActionListener) listener).onSuccess();
}
@@ -307,6 +299,7 @@
case REQUEST_ANQP_INFO_FAILED:
anqpRequestFinish((ScanResult) message.obj);
+ listener = getListener(message.arg2, false);
if (listener == null)
getListener(message.arg2, true);
if (listener != null) {
@@ -314,6 +307,31 @@
}
break;
+ case START_OSU_SUCCEEDED:
+ listener = getListener(message.arg2, true);
+ if (listener != null) {
+ ((OsuRemListener) listener).onSuccess();
+ }
+ break;
+
+ case START_OSU_FAILED:
+ listener = getListener(message.arg2, true);
+ if (listener != null) {
+ ((OsuRemListener) listener).onFailure(message.arg1);
+ }
+ break;
+
+ case START_OSU_BROWSER:
+ listener = getListener(message.arg2, true);
+ if (listener != null) {
+ ParcelableString str = (ParcelableString) message.obj;
+ if (str == null || str.string == null)
+ ((OsuRemListener) listener).onBrowserDismiss();
+ else
+ ((OsuRemListener) listener).onBrowserLaunch(str.string);
+ }
+ break;
+
default:
Log.d(TAG, "Ignored " + message);
break;
@@ -323,25 +341,46 @@
}
+ public static class ParcelableString implements Parcelable {
+ public String string;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(string);
+ }
+
+ public static final Parcelable.Creator<ParcelableString> CREATOR =
+ new Parcelable.Creator<ParcelableString>() {
+ @Override
+ public ParcelableString createFromParcel(Parcel in) {
+ ParcelableString ret = new ParcelableString();
+ ret.string = in.readString();
+ return ret;
+ }
+ @Override
+ public ParcelableString[] newArray(int size) {
+ return new ParcelableString[size];
+ }
+ };
+ }
+
private static final int BASE = Protocol.BASE_WIFI_PASSPOINT_MANAGER;
- /** @hide */
- public static final int REQUEST_ANQP_INFO = BASE + 1;
-
- /** @hide */
- public static final int REQUEST_ANQP_INFO_FAILED = BASE + 2;
-
- /** @hide */
- public static final int REQUEST_ANQP_INFO_SUCCEEDED = BASE + 3;
-
- /** @hide */
- public static final int REQUEST_OSU_INFO = BASE + 4;
-
- /** @hide */
- public static final int REQUEST_OSU_INFO_FAILED = BASE + 5;
-
- /** @hide */
- public static final int REQUEST_OSU_INFO_SUCCEEDED = BASE + 6;
+ public static final int REQUEST_ANQP_INFO = BASE + 1;
+ public static final int REQUEST_ANQP_INFO_FAILED = BASE + 2;
+ public static final int REQUEST_ANQP_INFO_SUCCEEDED = BASE + 3;
+ public static final int REQUEST_OSU_ICON = BASE + 4;
+ public static final int REQUEST_OSU_ICON_FAILED = BASE + 5;
+ public static final int REQUEST_OSU_ICON_SUCCEEDED = BASE + 6;
+ public static final int START_OSU = BASE + 7;
+ public static final int START_OSU_BROWSER = BASE + 8;
+ public static final int START_OSU_FAILED = BASE + 9;
+ public static final int START_OSU_SUCCEEDED = BASE + 10;
private Context mContext;
IWifiPasspointManager mService;
@@ -350,7 +389,6 @@
* TODO: doc
* @param context
* @param service
- * @hide
*/
public WifiPasspointManager(Context context, IWifiPasspointManager service) {
mContext = context;
@@ -368,7 +406,6 @@
* @return Channel instance that is necessary for performing any further
* passpoint operations
*
- * @hide
*/
public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
Messenger messenger = getMessenger();
@@ -387,8 +424,6 @@
/**
* STOPSHIP: temp solution, should use supplicant manager instead, check
* with b/13931972
- *
- * @hide
*/
public Messenger getMessenger() {
try {
@@ -398,7 +433,6 @@
}
}
- /** @hide */
public int getPasspointState() {
try {
return mService.getPasspointState();
@@ -407,7 +441,6 @@
}
}
- /** @hide */
public void requestAnqpInfo(Channel c, List<ScanResult> requested, int mask,
ActionListener listener) {
Log.d(TAG, "requestAnqpInfo start");
@@ -434,14 +467,16 @@
Log.d(TAG, "requestAnqpInfo end");
}
- /** @hide */
public void requestOsuIcons(Channel c, List<WifiPasspointOsuProvider> requested,
int resolution, ActionListener listener) {
}
- /** @hide */
public List<WifiPasspointPolicy> requestCredentialMatch(List<ScanResult> requested) {
- return null;
+ try {
+ return mService.requestCredentialMatch(requested);
+ } catch (RemoteException e) {
+ return null;
+ }
}
/**
@@ -450,7 +485,7 @@
*
* @return The list of credentials
*/
- public List<WifiPasspointCredential> getSavedCredentials() {
+ public List<WifiPasspointCredential> getCredentials() {
return null;
}
@@ -486,21 +521,21 @@
return true;
}
- /** @hide */
- public void startOsu(Channel c, WifiPasspointOsuProvider selected, OsuRemListener listener) {
-
+ public void startOsu(Channel c, WifiPasspointOsuProvider osu, OsuRemListener listener) {
+ Log.d(TAG, "startOsu start");
+ checkChannel(c);
+ int key = c.putListener(listener);
+ c.mAsyncChannel.sendMessage(START_OSU, 0, key, osu);
+ Log.d(TAG, "startOsu end");
}
- /** @hide */
- public void startUserRemediation(Channel c, OsuRemListener listener) {
+ public void startRemediation(Channel c, OsuRemListener listener) {
}
- /** @hide */
- public void connect(WifiPasspointPolicy selected) {
+ public void connect(WifiPasspointPolicy policy) {
}
private static void checkChannel(Channel c) {
- if (c == null)
- throw new IllegalArgumentException("Channel needs to be initialized");
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
}
}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
index f40dc4f..b54b70c 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
@@ -87,12 +87,12 @@
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
- sb.append("SSID: ").append(ssid);
+ sb.append("SSID: ").append("<").append(ssid).append(">");
if (friendlyName != null)
- sb.append(" friendlyName: ").append(friendlyName);
+ sb.append(" friendlyName: ").append("<").append(friendlyName).append(">");
if (serverUri != null)
- sb.append(" serverUri: ").append(serverUri);
- sb.append(" osuMethod: ").append(osuMethod);
+ sb.append(" serverUri: ").append("<").append(serverUri).append(">");
+ sb.append(" osuMethod: ").append("<").append(osuMethod).append(">");
if (iconFileName != null) {
sb.append(" icon: <").append(iconWidth).append("x")
.append(iconHeight).append(" ")
@@ -100,9 +100,9 @@
.append(iconFileName).append(">");
}
if (osuNai != null)
- sb.append(" osuNai: ").append(osuNai);
+ sb.append(" osuNai: ").append("<").append(osuNai).append(">");
if (osuService != null)
- sb.append(" osuService: ").append(osuService);
+ sb.append(" osuService: ").append("<").append(osuService).append(">");
return sb.toString();
}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
index 9fccf0a..f84ac88 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
@@ -16,10 +16,18 @@
package android.net.wifi.passpoint;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.ScanResult;
import android.os.Parcelable;
import android.os.Parcel;
+import android.security.Credentials;
import android.util.Log;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+
+
/** @hide */
public class WifiPasspointPolicy implements Parcelable {
@@ -43,6 +51,20 @@
private int mRestriction;// Permitted values are "HomeSP", "RoamingPartner", or "Unrestricted"
private boolean mIsHomeSp;
+ private final String INT_PRIVATE_KEY = "private_key";
+ private final String INT_PHASE2 = "phase2";
+ private final String INT_PASSWORD = "password";
+ private final String INT_IDENTITY = "identity";
+ private final String INT_EAP = "eap";
+ private final String INT_CLIENT_CERT = "client_cert";
+ private final String INT_CA_CERT = "ca_cert";
+ private final String INT_ANONYMOUS_IDENTITY = "anonymous_identity";
+ private final String INT_SIM_SLOT = "sim_slot";
+ private final String INT_ENTERPRISEFIELD_NAME ="android.net.wifi.WifiConfiguration$EnterpriseField";
+ private final String ISO8601DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+ private final String ENTERPRISE_PHASE2_MSCHAPV2 = "auth=MSCHAPV2";
+ private final String ENTERPRISE_PHASE2_MSCHAP = "auth=MSCHAP";
+
/** @hide */
public WifiPasspointPolicy(String name, String ssid,
String bssid, WifiPasspointCredential pc,
@@ -89,7 +111,7 @@
}
/** @hide */
- public boolean getHomeSp() {
+ public boolean isHomeSp() {
return mIsHomeSp;
}
@@ -121,6 +143,142 @@
return mRoamingPriority;
}
+ public WifiConfiguration createWifiConfiguration() {
+ WifiConfiguration wfg = new WifiConfiguration();
+ if (mBssid != null) {
+ Log.d(TAG, "create bssid:" + mBssid);
+ wfg.BSSID = mBssid;
+ }
+
+ if (mSsid != null) {
+ Log.d(TAG, "create ssid:" + mSsid);
+ wfg.SSID = mSsid;
+ }
+ //TODO: 1. add pmf configuration
+ // 2. add ocsp configuration
+ // 3. add eap-sim configuration
+ /*Key management*/
+ wfg.status = WifiConfiguration.Status.ENABLED;
+ wfg.allowedKeyManagement.clear();
+ wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+
+ /*Group Ciphers*/
+ wfg.allowedGroupCiphers.clear();
+ wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
+
+ /*Protocols*/
+ wfg.allowedProtocols.clear();
+ wfg.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+ wfg.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
+
+ Class[] enterpriseFieldArray = WifiConfiguration.class.getClasses();
+ Class<?> enterpriseFieldClass = null;
+
+
+ for(Class<?> myClass : enterpriseFieldArray) {
+ if(myClass.getName().equals(INT_ENTERPRISEFIELD_NAME)) {
+ enterpriseFieldClass = myClass;
+ break;
+ }
+ }
+ Log.d(TAG, "class chosen " + enterpriseFieldClass.getName() );
+
+
+ Field anonymousId = null, caCert = null, clientCert = null,
+ eap = null, identity = null, password = null,
+ phase2 = null, privateKey = null;
+
+ Field[] fields = WifiConfiguration.class.getFields();
+
+
+ for (Field tempField : fields) {
+ if (tempField.getName().trim().equals(INT_ANONYMOUS_IDENTITY)) {
+ anonymousId = tempField;
+ Log.d(TAG, "field " + anonymousId.getName() );
+ } else if (tempField.getName().trim().equals(INT_CA_CERT)) {
+ caCert = tempField;
+ } else if (tempField.getName().trim().equals(INT_CLIENT_CERT)) {
+ clientCert = tempField;
+ Log.d(TAG, "field " + clientCert.getName() );
+ } else if (tempField.getName().trim().equals(INT_EAP)) {
+ eap = tempField;
+ Log.d(TAG, "field " + eap.getName() );
+ } else if (tempField.getName().trim().equals(INT_IDENTITY)) {
+ identity = tempField;
+ Log.d(TAG, "field " + identity.getName() );
+ } else if (tempField.getName().trim().equals(INT_PASSWORD)) {
+ password = tempField;
+ Log.d(TAG, "field " + password.getName() );
+ } else if (tempField.getName().trim().equals(INT_PHASE2)) {
+ phase2 = tempField;
+ Log.d(TAG, "field " + phase2.getName() );
+
+ } else if (tempField.getName().trim().equals(INT_PRIVATE_KEY)) {
+ privateKey = tempField;
+ }
+ }
+
+
+ Method setValue = null;
+
+ for(Method m: enterpriseFieldClass.getMethods()) {
+ if(m.getName().trim().equals("setValue")) {
+ Log.d(TAG, "method " + m.getName() );
+ setValue = m;
+ break;
+ }
+ }
+
+ try {
+ // EAP
+ String eapmethod = mCredential.getType();
+ Log.d(TAG, "eapmethod:" + eapmethod);
+ setValue.invoke(eap.get(wfg), eapmethod);
+
+ // Username, password, EAP Phase 2
+ if ("TTLS".equals(eapmethod)) {
+ setValue.invoke(phase2.get(wfg), ENTERPRISE_PHASE2_MSCHAPV2);
+ setValue.invoke(identity.get(wfg), mCredential.getUserName());
+ setValue.invoke(password.get(wfg), mCredential.getPassword());
+ setValue.invoke(anonymousId.get(wfg), "anonymous@" + mCredential.getRealm());
+ }
+
+ // EAP CA Certificate
+ String cacertificate = null;
+ String rootCA = mCredential.getCaRootCertPath();
+ if (rootCA == null){
+ cacertificate = null;
+ } else {
+ cacertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.CA_CERTIFICATE + rootCA;
+ }
+ Log.d(TAG, "cacertificate:" + cacertificate);
+ setValue.invoke(caCert.get(wfg), cacertificate);
+
+ //User certificate
+ if ("TLS".equals(eapmethod)) {
+ String usercertificate = null;
+ String privatekey = null;
+ String clientCertPath = mCredential.getClientCertPath();
+ if (clientCertPath != null){
+ privatekey = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_PRIVATE_KEY + clientCertPath;
+ usercertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_CERTIFICATE + clientCertPath;
+ }
+ Log.d(TAG, "privatekey:" + privatekey);
+ Log.d(TAG, "usercertificate:" + usercertificate);
+ if (privatekey != null && usercertificate != null) {
+ setValue.invoke(privateKey.get(wfg), privatekey);
+ setValue.invoke(clientCert.get(wfg), usercertificate);
+ }
+ }
+ } catch (Exception e) {
+ Log.d(TAG, "createWifiConfiguration err:" + e);
+ }
+
+ return wfg;
+ }
+
/** {@inheritDoc} @hide */
public int compareTo(WifiPasspointPolicy another) {
Log.d(TAG, "this:" + this);
@@ -128,11 +286,11 @@
if (another == null) {
return -1;
- } else if (this.mIsHomeSp == true && another.getHomeSp() == false) {
+ } else if (this.mIsHomeSp == true && another.isHomeSp() == false) {
//home sp priority is higher then roaming
Log.d(TAG, "compare HomeSP first, this is HomeSP, another isn't");
return -1;
- } else if ((this.mIsHomeSp == true && another.getHomeSp() == true)) {
+ } else if ((this.mIsHomeSp == true && another.isHomeSp() == true)) {
Log.d(TAG, "both HomeSP");
//if both home sp, compare credential priority
if (this.mCredentialPriority < another.getCredentialPriority()) {
@@ -160,7 +318,7 @@
} else {
return 1;
}
- } else if ((this.mIsHomeSp == false && another.getHomeSp() == false)) {
+ } else if ((this.mIsHomeSp == false && another.isHomeSp() == false)) {
Log.d(TAG, "both RoamingSp");
//if both roaming sp, compare roaming priority(preferredRoamingPartnerList/<X+>/priority)
if (this.mRoamingPriority < another.getRoamingPriority()) {